Programmierung Archives - Technik - Blogbasis.net https://technik.blogbasis.net/category/programmierung Die Basis des freien Wissens – Technik Fri, 13 May 2016 19:09:20 +0000 de hourly 1 https://wordpress.org/?v=6.8.1 RaspberryPi + DS18B20 = ThermometerPi https://technik.blogbasis.net/raspberrypi-ds18b20-thermometerpi-13-05-2016 https://technik.blogbasis.net/raspberrypi-ds18b20-thermometerpi-13-05-2016#respond Fri, 13 May 2016 18:34:21 +0000 http://technik.blogbasis.net/?p=1393 Ich bin vor einigen Wochen über einen Blogpost gestoßen, in dem erklärt wurde, wie man aus einem RaspberryPi und einem Wärmesensor (DS18B20) sich ein eigenes Thermometer bauen kann. Dieser Idee bin ich nachgegangen und möchte in diesem Blogpost beschreiben, welche Tweaks dabei nötig waren.

Irgendwo auf Twitter oder einem anderen Medium habe ich ein Link zu dem Blogpost „[Tutorial] DS18S20 Temperatur Sensor an einem Raspberry Pi“ gefunden. Das hat mich so sehr fasziniert, dass ich das nachbauen wollte.

Dazu bestellte ich mir auf Amazon zunächst 10 solcher Sensoren mit entsprechend langem Kabel und Abdichtung: 10 x DS18B20 Digitale Temperaturfühler für ~15€. Dazu kamen noch ein paar 4.7k Ohm Widerstände. Nach ein paar Tagen war alles in meinem Briefkasten. Angeblich kann man sich von Maximintegrated ein kostenloses Sample zuschicken lassen. Allerdings kam bei mir bisher nichts an, vielleicht auch einfach Pech oder ein Fehler auf meiner Seite.

Aufbau

Für die Verkabelung des Sensors mit dem RaspberryPi bin ich den Schritten in dem oben genannten Blogpost gefolgt. Für mehr Informationen möchte ich dorthin verweisen.

Quelle: https://kopfkino.irosaurus.com/tutorial-ds18s20-temperatur-sensor-an-einem-raspberry-pi/

Quelle: https://kopfkino.irosaurus.com/tutorial-ds18s20-temperatur-sensor-an-einem-raspberry-pi/

Wichtig ist scheinbar nur, dass man den GPIO-Pin 4 nutzt. Ich habe es selbst nicht mit anderen GPIO-Pins probiert. Wenn es bei euch mit anderen klappt, bitte einen kurzen Kommentar hinterlassen.

Konfiguration

Ich habe auf meinem RaspberryPi Archlinux mit einem halbwegs aktuellen Kernel am Laufen. Das führte dazu, dass die weiteren Schritte in dem oben genannten Blogpost nicht funktionierten. Nachdem ich ein wenig recherchiert habe, kam ich zu einer klein wenig modifizierten Lösung.

Zunächst muss man in die /boot/config.txt folgende Zeile anhängen:

dtoverlay=w1-gpio,gpiopin=4,pullup=on

Danach muss man noch Kernelmodule laden. Dies erledigt man am Besten direkt beim Booten, in dem man folgendes in die Datei /etc/modules einträgt:

w1-gpio pullup=1
w1_therm

Nach einem Neustart sollte der Sensor unter  „/sys/bus/w1/devices/<sensor-id>“ verfügbar sein. Mit folgendem Einzeiler kriegt man die aktuelle Temperatur heraus:

$> cat /sys/bus/w1/devices/28-041621eb50ff/w1_slave | grep -oP "t=(\d+)" | sed -e "s/t=//g"
21687

Automatisierung & Webseite

Ich wollte mir eine kleine grafische Ansicht über den Temperaturverlauf bauen. Dazu entschied ich mich, die Daten von zwei Sensoren (1x Indoor, 1x Outdoor) alle 30 Sekunden auszulesen und in eine SQLite3-Datenbank zu schreiben.

Dazu habe ich zwei Scripte unter „/opt/thermo/“ zu liegen. Das Erste kümmert sich nur um das Auslesen der Daten und heißt „data.sh“:

#!/bin/bash

outdoor=$(cat /sys/bus/w1/devices/28-041621eb50ff/w1_slave | grep -oP "t=(\d+)" | sed -e "s/t=//g")
indoor=$(cat /sys/bus/w1/devices/28-041621fadbff/w1_slave | grep -oP "t=(\d+)" | sed -e "s/t=//g")
seconds=$(TZ=Europe/Berlin date +"%s")

echo "$seconds,$indoor,$outdoor"

Die IDs müssen natürlich entsprechend angepasst werden.

Das zweite Script „insertdata.sh“ ruft „data.sh“ auf und schreibt die Daten in eine SQLite3-Datenbank.

#!/bin/bash
olddir=$(pwd)
cd /opt/thermo/
sqlite3 thermo.sqlite3 "insert into temperatures VALUES ($(./data.sh));"
cd "$olddir"

Da Archlinux mit Systemd kommt, können wir dessen Timer nutzen, um die Aufgabe alle 30 Sekunden abzufeuern. Dazu legen wir zunächst den Service unter „/etc/systemd/system/thermo.service“ an:

[Unit]
Description=Thermometer data collector

[Service]
Type=oneshot
ExecStart=/bin/bash /opt/thermo/insertdata.sh

Der Timer „/etc/systemd/system/thermo.timer“ führt diesen Service dann periodisch aus:

[Unit]
Description=Thermo data collector timer

[Timer]
Persistent=true
OnUnitActiveSec=30s
OnBootSec=30s

[Install]
WantedBy=timers.target

Diesen muss man mit einem kurzem Kommando aktivieren:

sudo systemctl enable thermo.timer

Zuletzt fehlte nur noch eine kleine Webseite, die die Daten aus der SQLite-Datenbank ausliest und anzeigt. Dazu habe ich einfach Apache + PHP installiert und folgende „index.php“ im DocumentRoot abgelegt.

thermo-website

<html>
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.0.0/Chart.js"></script>
</head>
<body class="container">
<?php
$db = new SQLite3('/opt/thermo/thermo.sqlite3');
$beginOfDay = strtotime("midnight", time());

$current = $db->query('SELECT * FROM temperatures order by timestamp desc limit 1');
$row = $current->fetchArray();

$currentDate = date("H:i:s - d.m.Y", $row['timestamp']);
$currentIndoor = round($row['indoor']/1000,3);
$currentOutdoor = round($row['outdoor']/1000,3);

$minmax = $db->query("SELECT MIN(indoor) as minIndoor, MIN(outdoor) as minOutdoor, MAX(indoor) as maxIndoor, MAX(outdoor) as maxOutdoor FROM temperatures where timestamp >= $beginOfDay order by timestamp desc");
$row = $minmax->fetchArray();

$minIndoor = round($row['minIndoor']/1000,3);
$maxIndoor = round($row['maxIndoor']/1000,3);
$minOutdoor = round($row['minOutdoor']/1000,3);
$maxOutdoor = round($row['maxOutdoor']/1000,3);

echo "<h1>Last measurement: $currentDate</h1>";
echo "<table class='table'><tr><th>Location</th><th>Current °C</th><th>Todays Min °C</th><th>Todays Max °C</th></tr>";
echo "<tr><td>Indoor</td><td>$currentIndoor</td><td>$minIndoor</td><td>$maxIndoor</td>";
echo "<tr><td>Outdoor</td><td>$currentOutdoor</td><td>$minOutdoor</td><td>$maxOutdoor</td>";
echo "</table>";

?>
<canvas id="myChart" width="300" height="100"></canvas>

<?php
$minmax = $db->query("SELECT * FROM temperatures where timestamp >= $beginOfDay order by timestamp asc");
$labels = array();
$indoor = array();
$outdoor = array();
$diff = array();
while($row = $minmax->fetchArray()) {
    $labels[] = date("H:i:s", $row['timestamp']);
    $indoor[] = round($row['indoor']/1000,3);
    $outdoor[] = round($row['outdoor']/1000,3);
    $diff[] = abs(round((abs($row['indoor']) - abs($row['outdoor']))/1000,3));
}
?>

<script>
var data = {
    labels: <?php echo json_encode($labels); ?>,
    datasets: [
        {
            label: "Indoor",
            fill: false,
            lineTension: 0.1,
            backgroundColor: "rgb(209,12,8)",
            borderColor: "rgb(209,12,8)",
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: "rgb(209,12,8)",
            pointBackgroundColor: "#fff",
            pointBorderWidth: 1,
            pointHoverRadius: 5,
            pointHoverBackgroundColor: "rgb(209,12,8)",
            pointHoverBorderColor: "rgba(220,220,220,1)",
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            pointHitRadius: 10,
            data: <?php echo json_encode($indoor);?>,
        },
        {
            label: "Outdoor",
            fill: false,
            lineTension: 0.1,
            backgroundColor: "rgb(8,209,8)",
            borderColor: "rgb(8,209,8)",
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: "rgb(8,209,8)",
            pointBackgroundColor: "#fff",
            pointBorderWidth: 1,
            pointHoverRadius: 5,
            pointHoverBackgroundColor: "rgb(8,209,8)",
            pointHoverBorderColor: "rgba(220,220,220,1)",
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            pointHitRadius: 10,
            data: <?php echo json_encode($outdoor);?>,
        },
        {
            label: "Difference",
            fill: false,
            lineTension: 0.1,
            backgroundColor: "rgba(75,192,192)",
            borderColor: "rgba(75,192,192)",
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: "rgba(75,192,192)",
            pointBackgroundColor: "#fff",
            pointBorderWidth: 1,
            pointHoverRadius: 5,
            pointHoverBackgroundColor: "rgba(75,192,192)",
            pointHoverBorderColor: "rgba(220,220,220,1)",
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            pointHitRadius: 10,
            data: <?php echo json_encode($diff);?>,
        }
    ]
};

var ctx = document.getElementById("myChart");
var myLineChart = new Chart(ctx, {
    type: 'line',
    data: data,
});
</script>
</body>
</html>

~ Sebastian

]]>
https://technik.blogbasis.net/raspberrypi-ds18b20-thermometerpi-13-05-2016/feed 0
Gitignore.io – Kleines Werkzeug zum .gitignore Erstellen https://technik.blogbasis.net/gitignore-io-kleines-werkzeug-zum-gitignore-erstellen-09-11-2014 https://technik.blogbasis.net/gitignore-io-kleines-werkzeug-zum-gitignore-erstellen-09-11-2014#respond Sun, 09 Nov 2014 18:44:42 +0000 http://technik.blogbasis.net/?p=1257 Hallo Leute,

diesmal nur eine kurze Vorstellung eines sehr nützlichen Tools zum Erstellen von .gitignore Dateien für bestimmte Sprachen/Frameworks.

Es handelt sich um die sehr schlicht gehaltene Webseite „Gitignore.io„.

Dort trägt man einfach beliebig viele Sprachen/Frameworks, für die man passende .gitignore-Einträge haben möchte, ein. Nach einem Klick auf „Generate“ bekommt man eine Copy-Paste-Übersicht über alle nötigen Einträge.

Das nächste nennenswerte Feature ist die API (Doku). In dieser wird gezeigt, wie man für fast alle Kommandozeilenprogramme eine Funktion einrichtet, welche auf Wunsch die entsprechende .gitignore Datei erstellt.

Beispiel:

echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bashrc && source ~/.bashrc

Kann so genutzt werden:

[user@host ~]$ gi java
# Created by https://www.gitignore.io

### Java ###
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

Viel Spaß damit!

~ Sebastian

 

]]>
https://technik.blogbasis.net/gitignore-io-kleines-werkzeug-zum-gitignore-erstellen-09-11-2014/feed 0
NodeJS Simple Linklist https://technik.blogbasis.net/nodejs-simple-linklist-23-09-2014 https://technik.blogbasis.net/nodejs-simple-linklist-23-09-2014#respond Tue, 23 Sep 2014 08:09:20 +0000 http://technik.blogbasis.net/?p=1176 Hallo Leute,

heute gibt es etwas Code für euch. Irgendwie kam mir die Idee, das die Welt ein kleines, einfaches, dateibasiertes Linklisten-Script in NodeJs gebrauchen könnte. Nach ein paar wenigen Codezeilen war das Projekt dann auch schon umgesetzt.

Screenshot

Simple Linklist Screenshot

Simple Linklist Screenshot

Features

Die Featureliste ist relativ klein, da das Script nicht viel können muss und entsprechend einfach gehalten wurde. Das wahrscheinlich wichtigste Feature ist die Speicherung der Links als Dateien im Dateisystem. D.h. es wird keine Datenbank benötigt.

  • TreeView
  • Caching (RAM/Disk)
  • Link description
  • Flat-file „database“

Installation

Die Installation ist entsprechend einfach. Es gibt folgende Voraussetzungen:

  • NodeJS
  • NPM

Sind diese erfüllt, so klont man das Repository und folgt den offensichtlichen Schritten:

git clone git@github.com:gehaxelt/Nodejs-Simple-Linklist.git
cd Nodejs-Simple-Linklist
npm install

Zuletzt muss man noch zwei beschreibbare Ordner erstellen:

mkdir cache links

Entscheidet man sich bei der Konfiguration für den RAM-Cache, so brauch der „cache“ Ordner nicht erstellt werden.

Konfiguration

Es existiert eine „config.js.example“, welche man zunächst übernehmen kann:

cp config.js.example config.js

Möchte man die IP + Port der Webbapplikation bzw. das Caching-Verhalten anpassen, so sollte man einen Blick in diese Datei rein werfen. Wird „ramcache: false“ gesetzt, so wird die Festplatte als Cache genutzt.

Benutzung

Kategorien

Die Benutzung ist sehr einfach gehalten. Für eine neue Kategorie muss man einen neuen Ordner im „links“-Ordner erstellen. Dabei beachtet das Script Verschachtelung. D.h. für eine Unterkategorie muss entsprechend ein Unterordner angelegt werden. Der Name des Ordners ist gleichzeitig der Name der Kategorie. Auf Linuxsystemen hat man mehr Spielraum mit den Sonderzeichen.

Links

Um neue Links in einer Kategorie anzulegen, muss einfach eine Datei in dem entsprechenden Ordner angelegt werden. Der Name der Datei ist dabei der „Name“ des angezeigten Links. Der Inhalt der Datei sollte dabei folgender Struktur folgen:

cat Linkname
URL
Beschreibung

Beispiel:

cat example.com
http://example.com/foo
An example website
Führt zu <a href="http://example.com/foo">example.com - An example website</a>

Zum Testen kann man einen Blick in den „links.example“ Ordner werfen.

Updating der Webseite

Die Webseite aktualisiert sich nach einer Änderung der Links/Kategorien im „links“ Ordner nicht automatisch, da diese Informationen im Cache gehalten werden. Möchte man ein Update erzwingen, so muss man eine (leere) „update.txt“ Datei im „links“ Ordner anlegen:

touch links/update.txt

Beim nächsten Aufruf der Webseite wird diese Datei erkannt, ein Update des Caches durchgeführt und die Datei gelöscht.

Man kann also wunderbar per „rsync“ seine Linkliste mit dem Webserver synchronisieren.

Abschluss

Das Projekt ist unter GPLv3 released und man findet den Source auf GitHub. Ich hoffe es gefällt euch. Verbesserungen bzw. Kommentare sind gerne gesehen.

Grüße,
Sebastian

]]>
https://technik.blogbasis.net/nodejs-simple-linklist-23-09-2014/feed 0
Wenn eclipse nach ein paar Zeilen Code abstürzt. https://technik.blogbasis.net/wenn-eclipse-nach-ein-paar-zeilen-code-abstuerzt-14-03-2014 https://technik.blogbasis.net/wenn-eclipse-nach-ein-paar-zeilen-code-abstuerzt-14-03-2014#respond Fri, 14 Mar 2014 18:00:21 +0000 http://technik.blogbasis.net/?p=1050 Ich hab mich letztens mal wieder an eine Android App gewagt. Dafür dann die ADT runtergeladen und daraus eclipse gestartet. Nach wenigen Zeichen bzw. Zeilen Code stürzte Eclipse aus unerklärlichen Gründen ab. Zum Glück gibt es einen kurzen Fix dafür.

Eclipse stürzte mit der folgenden Fehlermeldung ab:

gehaxelt@LagTop ~/android/eclipse % ./eclipse 
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f51b3dacbd1, pid=10934, tid=139991535183616
#
# JRE version: OpenJDK Runtime Environment (7.0_51-b31) (build 1.7.0_51-b31)
# Java VM: OpenJDK 64-Bit Server VM (24.51-b03 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libsoup-2.4.so.1+0x6fbd1]  soup_session_feature_detach+0x11
#
# Core dump written. Default location: /home/gehaxelt/android/eclipse/core or core.10934
#
# An error report file with more information is saved as:
# /home/gehaxelt/android/eclipse/hs_err_pid10934.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
#   http://icedtea.classpath.org/bugzilla
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
./eclipse  21,39s user 1,54s system 85% cpu 26,746 total

Im Bugtracker von Eclipse gibt es dafür einen Workaround:

Man muss einfach in die „eclipse.ini“ folgenden String eintragen:

-Dorg.eclipse.swt.browser.DefaultType=mozilla

Danach sollte Eclipse wieder ohne Probleme laufen. Zumindest hatte das bei mir geholfen.

Viele Grüße,

~Sebastian

]]>
https://technik.blogbasis.net/wenn-eclipse-nach-ein-paar-zeilen-code-abstuerzt-14-03-2014/feed 0
Mit Piwik Klicks auf Element tracken – _paq undefined https://technik.blogbasis.net/mit-piwik-klicks-auf-element-tracken-_paq-undefined-05-03-2014 https://technik.blogbasis.net/mit-piwik-klicks-auf-element-tracken-_paq-undefined-05-03-2014#respond Tue, 04 Mar 2014 23:09:36 +0000 http://technik.blogbasis.net/?p=1039 Langsam verfalle ich auch der Datensammelwut. Eine Person hat sich auf einer meiner Webseiten einen Bannerplatz gemietet und mich interessiert,es wie viele Personen auf das Banner klicken. Piwik bietet einem mit den „benutzerdefinierten Variablen“ die Möglichkeit bestimmte Events zu tracken. Leider funktionieren die Beispielcodes aus der Dokumentation nicht wirklich. Daher hier ein kleiner Workaround dafür.

Da die gefundenen Tutorials bzw. die offizielle Dokumentation nicht wie erwartet funktioniert hat, beschreibe ich nun meinen kleinen Workaround.

Wir stellen uns also die folgende Webseite bzw. den folgenden Codeausschnitt vor:

<img src="http://" id="top_banner" />

Das ist also unser Bild. Wenn ein Besucher darauf klickt, so wollen das mitzählen.

In den oben genannten Quellen findet sich dazu der folgende Quelltext bzw. die folgende Umsetzung:

<img src="http://" id="top_banner" onclick="javascript:_paq.push(['setCustomVariable',1,'top_banner','page']);"/>

Wenn man in Piwik asynchrones Tracking aktiviert hat, so wird in dem generierten Quelltext das Array „_paq“ erzeugt. In dieses Array kann man Ereignisse pushen, welche dann vom Tracker abgearbeitet werden.  Die Initialisierung packt man normalerweise in einen eigenen Script-Block am unteren Ende des Bodys einer Webseite.

Das Problem bestand dann darin, dass in den on*-Enventhandlern das „_paq“-Array nicht mehr bekannt, also „undefined“, war. Demnach wurde auch nichts getrackt.

Die Lösung war dann einfach das folgende Stückchen Javascript:

document.getElementById("top_banner").addEventlistener('click',function() {
   _paq.push(['setCustomVariable',1,'top_banner','page'])
},false);

Diesen Einzeiler packt man einfach mit zum Piwik Trackingcode. Da der Code dann im gleichen Kontext behandelt wird, ist das „_paq“ Array auch bekannt und alles funktioniert wie erwartet.

]]>
https://technik.blogbasis.net/mit-piwik-klicks-auf-element-tracken-_paq-undefined-05-03-2014/feed 0
Symfony2 – Auf Servicecointainer im Validator zugreifen https://technik.blogbasis.net/symfony2-auf-miner-31-01-2014 https://technik.blogbasis.net/symfony2-auf-miner-31-01-2014#respond Fri, 31 Jan 2014 02:20:32 +0000 http://technik.blogbasis.net/?p=1031 In der letzten Zeit arbeite ich verstärkt mit dem Symfony2 Framework. Bei dem letzten Projekt kam es zu der Gegebenheit, dass ich aus dem einer eigenen Validatorklasse auf Parameter in der parameters.yml zugreifen musste. Das klappt aber nur mit dem Umweg über den Servicecontainer.

Die Validatorklasse

Ich nehme mal an, man schreibt sich eine eigenen Validator. Dieser besteht normalerweise aus zwei Dateien:

<?php
// src/Acme/DemoBundle/Validator/Contrainsts/UpperCase.php
namespace Acme\DemoBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class UpperCase extends Constraint
{
    public $message = 'The string "%string%" is not in uppercase format.';

    public function validatedBy()
    {
        return 'uppercasevalidator';
    }
}

Diese Klasse gibt an sich nur die Fehlermeldung aus. Auf die Funktion „validateBy()“ komme ich später zurück.

Nun brauchen wir noch den eigentlichen Validierungscode, den wir in der folgenden Datei ablegen:


<?php 
//src/Acme/DemoBundle/Validator/Contrainsts/UpperCaseValidator.php
namespace Acme\DemoBundle\Validator\Constraints; 
use Symfony\Component\Validator\Constraint; 
use Symfony\Component\Validator\ConstraintValidator; 

class UpperCaseValidator extends ConstraintValidator {     

    public function validate($value, Constraint $constraint)     {
         if (!$this->ctype_upper($value) && $this->container-getParameter('validator.active')) {
            $this->context->addViolation($constraint->message, array('%string%' => $value));
        }
    }

    protected $container;

    public function __construct($container){
        $this->container = $container;
    }

}

Das Beispiel ist zwar etwas doof gewählt, aber wir nehmen mal an, dass man unbedingt im Validator auf Parameter aus der „parameters.yml“ zugreifen muss.

Die Konfiguration

Nach ein wenig Recherche bin ich auf eine Lösung des Problems gestoßen, welche ich nun gerne mit euch teilen möchte.

Um zum Ziel zu gelangen, muss man in der „app/config/config.yml“ einen neuen Bereich einführen:

services:
    validator.unique.test:
        class: "Acme\DemoBundle\Validator\Constraints\UpperCaseValidator"
        arguments: [@service_container]
        tags:
            - { name: validator.constraint_validator, alias: uppercasevalidator }

Das wichtige dabei ist, dass

  • Die Pfadangabe unter „class“ keine Tippfehler enthält
  • Der „alias“-Parameter genauso heißt, wie die Rückgabe der Funktion „validateBy()“.

Ansonsten sollte der Rest des Codes soweit verständlich sein. Die Konfiguration übergibt der Validator-Klasse den Servicecontainer als Argument, und diesen fangen wir im Konstruktor auf. Danach können wir den ganz normal innerhalb des Validators nutzen.

~Sebastian

]]>
https://technik.blogbasis.net/symfony2-auf-miner-31-01-2014/feed 0
WordPress-Multisite – Liste mit Artikeln der Unterblogs https://technik.blogbasis.net/wordpress-multisite-liste-mit-artikeln-der-unterblogs-31-01-2014 https://technik.blogbasis.net/wordpress-multisite-liste-mit-artikeln-der-unterblogs-31-01-2014#respond Fri, 31 Jan 2014 01:00:02 +0000 http://technik.blogbasis.net/?p=1025 Nachdem sich der Arndt einige Male bei mir beschwert hat, dass er doch gerne auf „blogbasis.net“ eine Übersicht aller auf den Subblogs geschriebener Artikel haben würde, musste ich mir was einfallen lassen.

Im Endeffekt reicht ein wenig Template umcoden und die schöne WordPress Multisite API, um das gewünschte Feature umzusetzen.

Welches Template?

Zunächst stellte sich mir die Frage, welche Templatedatei man anpassen musste. Ich hatte nämlich vor, die „normale“ Hauptseite eines WordPressblogs mit eigenem Inhalt zu überschreiben.

Nach ein wenig stöbern im Template-Editor entschied ich mich für die „Hauptseitendatei (index.php)“.

Die Idee!

Dort findet man ein paar if-Konstrukte und einige Schleifen, um die entsprechenden Daten schön aufzubereiten. Genau diese Funktionalitäten brauchte ich. Nur wie kann man ohne weitere Mühe von einem Subblog auf die Posts der anderen Blogs zugreifen?

Nach ein wenig googeln entdeckte ich eine sehr nützliche Übersicht an WordPress-Multisite-Funktionalitäten: http://codex.wordpress.org/WPMU_Functions

Dort gab es eine Funktion namens „switch_to_blog($id)“. Diese Funktion behielt ich erstmal im Hinterkopf.

Das nächste Problem was sich stellte war folgendes: Da ich für alle Subblogs dasselbe Theme verwende, würde ich durch eine Änderung der „index.php“ auf allen Subblogs nur die Übersicht der Artikel zeigen. Das ist natürlich nicht gewollt. Nach ein wenig Debugging und weiteren Recherchen bzw. der oben verlinkten Dokumentation, entschied ich mich die verschiedenen Subblogs mittels „get_bloginfo(’name‘)“ zu unterscheiden.

Die Funktion liefert uns sehr viele nützliche Informationen über den gerade besuchten (Sub)blog. Da die Namen der Blogs eindeutig sind, konnte ich darüber die Unterscheidung laufen lassen, um die Übersicht nur auf „blogbasis.net“ anzeigen zu lassen.  Für die restlichen Blogs würde dann einfach der „else“-Zweig greifen, und alles ist gut.

Zuallerletzt musste ich noch eine umständliche Methode zum Auslesen bzw. Durchlaufen der einzelnen Posts schreiben, da die einfache „loop“ komischerweise nicht laufen wollte.

Der Code

Lange Rede, kurzer Sinn. Code-mäßig sieht die neue index.php dann so aus: (Nur der obere Teil sollte interessant sein. Der Rest bleibt nur der Vollständigkeit halber.)

[gist id=“8cab54003d119896f252″]

Fazit

Man sollte jetzt nicht mehr das Theme updaten, da sonst die Veränderungen wahrscheinlich verloren gehen :D

Ich denke, dass die Übersicht aller Unterbeiträge auf „blogbasis.net“ eine ganz gute Idee vom Arndt gewesen ist, und dass mir die Umsetzung halbwegs gelungen ist.

PS: Sorry für die Rechtschreibung, aber ich habe nicht nochmal drüber gelesen.

~Sebastian

]]>
https://technik.blogbasis.net/wordpress-multisite-liste-mit-artikeln-der-unterblogs-31-01-2014/feed 0
[C-Codeschnipsel] Progress Bar https://technik.blogbasis.net/c-codeschnipsel-progress-bar-30-01-2014 https://technik.blogbasis.net/c-codeschnipsel-progress-bar-30-01-2014#respond Wed, 29 Jan 2014 23:07:07 +0000 http://technik.blogbasis.net/?p=1021 Der folgende Codeschnipsel zaubert eine Fortschrittsanzeige ins Terminal:

void printProgress(int p, int len)
{
    int curlen = (p * len) / 100, i;
    printf("\r");
    for(i = 0; i < curlen; ++i)
        putc('_', stdout);
    putc('X', stdout);
    while(i++ < len) 
        putc(' ', stdout);
    printf("|%d%%", p);
    fflush(stdout);
}

p ist der Prozentsatz zwischen 0 und 100, len ist die Länge des Balkens. (in chars)

Wird die Funktion wiederholt aufgerufen und dazwischen keinerlei andere Ausgaben durchgeführt, wird die neue Fortschrittsleiste ersetzt.

]]>
https://technik.blogbasis.net/c-codeschnipsel-progress-bar-30-01-2014/feed 0
Mit Awesome und curl den aktuellen DOGE/BTC-Kurs im Blick haben https://technik.blogbasis.net/mit-awesome-und-curl-den-aktuellen-dogebtc-kurs-im-blick-haben-27-01-2014 https://technik.blogbasis.net/mit-awesome-und-curl-den-aktuellen-dogebtc-kurs-im-blick-haben-27-01-2014#respond Mon, 27 Jan 2014 01:13:28 +0000 http://technik.blogbasis.net/?p=1013 Wenn man Leute beobachtet, die sich viel mit Crypto-Währungen beschäftigt fällt auf, dass immer wieder Webseiten aufgerufen werden um den aktuellen Kurs zu erfahren. Dass muss nicht sein. Denn mit einer API kann man die Kurse auch durch ein Programm abrufen lassen. Wenn man Linux nutzt geht das recht schnell. Hier will ich kurz zeigen wie man sich für Awesome ein kleines Wiget für diese Aufgabe schreibt.

Erstmal braucht man eine Möglichkeit um den aktuellen Kurs zu erfahren.

Wenn es schon eine API gibt ist das natürlich praktisch. Durch Googeln von „Dogecoin API Price“ bekommt man einen nützlichen Beitrag auf Reddit. Dort gibt es dann auch gleich einen Link auf eine Web-API. Die kann man dann dank curl auch direkt von der Shell aus nutzen.

curl https://bter.com/api/1/ticker/doge_btc

gibt einem

{"result":"true","last":"0.00000184","high":"0.00000220","low":"0.00000180","avg":"0.00000195","sell":"0.00000185","buy":"0.00000182","vol_doge":395657724.31,"vol_btc":769.703167}%

zurück. Für ein Widget muss man sich die Ausgabe dann nur noch etwas formatieren. Ich hab das erstmal mit einem Ruby-Skript gemacht. Denn hier gibt es das coole Tool Rubular.

cmd = `curl -s http://bter.com/api/1/ticker/doge_btc`
regex = /last\":\"([0-9\.]+)/
cap = cmd.match(regex).captures
p cap[0]

das geht also alles soweit erstmal.

Jetzt ein Awesome-Wiget schreiben:

Erstmal braucht man eine rc.lua . Hier kann man jetzt an einer geeigneten stelle den Lua-Code für das Widget einfügen. Der sieht dann so aus:

--Create a Doge-Notifier, which shows the number of doge/BTC
mydogeStatus = widget({ type = "textbox" })
mydogeStatus.text ="Doge-Notifier init"

mydogeStatustimer = timer({ timeout = 5 })
mydogeStatustimer:add_signal("timeout", function()

mydogeStatus.text = "Doge/BTC: ".. awful.util.pread([[curl -s http://bter.com/api/1/ticker/doge_btc | grep -m 1 -ioP 'last":"([0-9\.]+)' | sed -e 's/last":"//g']])

end
)
mydogeStatustimer:start()

So das wars auch schon: Den Code hier drüber kann man einfach in seine rc.lua Copy-Pasten und dann noch das „mydogeStatus“ in die entsprechende Widgetbox (oft wibox) packen.

Im Code hier verwende ich kein Ruby mehr, dass war zu ineffizient (Warum eigentlich?). Egal bash-Magie tuts ja auch. Wenn man es klüger machen kann kannst du es ja mit einem Kommentar mitteilen (wäre sogar sehr nett).

]]>
https://technik.blogbasis.net/mit-awesome-und-curl-den-aktuellen-dogebtc-kurs-im-blick-haben-27-01-2014/feed 0
WinAPI Crypting https://technik.blogbasis.net/winapi-crypting-08-10-2013 https://technik.blogbasis.net/winapi-crypting-08-10-2013#respond Tue, 08 Oct 2013 13:32:39 +0000 http://technik.blogbasis.net/?p=555 Vorwort

Dieser etwas kleinere Artikel dreht sich um das Thema WinAPI-Crypting.
Warum sollte man sich damit überhaupt befassen?
API-Crypting ist immer dann hilfreich, wenn man möchte, dass erst während der Laufzeit bekannt wird, welche Funktionen aufgerufen werden. Zum Beispiel wenn man das Leben eines Reversers erschweren möchte oder ähnliches.

Was steckt hinter dem API-Crypting

Umgang mit Dlls

Unter Windows haben wir die Möglichkeit eine beliebige Dll-Datei zu laden und alle Funktionen, die diese Dll anbietet, aufzurufen. Dabei müssen wir nur den Namen der Dll und den Funktionsnamen kennen.
Das ganze arbeitet dann mit den drei Funktionen LoadLibrary, GetProcAddress und FreeLibrary. LoadLibrary lädt eine beliebige Dll-Datei in den virtuellen Speicher des aufrufenden Prozesses und gibt dabei ein Handle zu dieser Dll zurück. GetProcAddress durchsucht dann die Export-Tabelle, also die Tabelle in der alle Funktionen stehen, die außerhalb des Moduls angesprochen werden können, nach unserer Funktion und gibt die Addresse zurück. FreeLibrary entlädt die Dll aus dem aufrufenden Prozess.

HMODULE WINAPI LoadLibrary(LPCTSTR lpFileName);
FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName);
BOOL WINAPI FreeLibrary(HMODULE hModule);

Funktionszeiger

C++ ermölicht es Objekte über ihre Addresse anzusprechen. Doch warum sollte man dies nur auf Objekte beschränken. Durch type-defines können wir sogenannte Funktionszeiger definieren und diese auf eine Addresse im speicher setzen.
Anschließend können wir diese Funktionszeiger wie normale Funktionen aufrufen.

typedef int (WINAPI * MessageBoxPtr)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
MessageBoxPtr Message = Addresse;
Message(0,"Durch Funktionszeiger aufgerufen","Information",0);

Das Vorgehen beim WinAPI-Crypting

Zunächst benötigen wir folgendes
– den Namen der Funktion in der Export-Tabelle
– den Namen der Dll-Datei in der die Funktion enthalten ist.
– einen Funktionszeigern, den wir auf die Addresse im Speicher setzen können

Der Funktionsname als auch der Name der Dll-Datei werden als verschlüsselte Strings im SRC gespeichert.
Beim Ausführen des Programms werden die Strings entschlüsselt, die Dll in den Prozesspeicher geladen und ein Funktionszeiger auf die Addresse der Funktion gesetzt. Zuletzt kann man den Funktionszeiger wie gewohnt aufrufen.

Ein kleines Beispiel

Angenommen wir möchten folgenden SRC mithilfe von WinAPI-Crypting verschlüsseln

#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
    MessageBoxA(0,"Normaler Funktionsaufruf","Information",0);
    return 0;
}

Der einzige WinAPI-Aufruf den wir haben ist der Aufruf von MessageBoxA und durch die MSDN erfahren wir, dass die Funktion in der Dll „User32.dll“ als Ascii-Funktion (MessageBoxA) und als Unicode(Widechar)-Funktion (MessageBoxW) enthalten ist. Also schnell einen Funktionszeiger gebastelt, die Dll per LoadLibraryA laden lassen und die Funktionsaddresse per GetProcAddress() erhalten. Ich hab in dem folgenden Code schon den Namen der Dll und den Namen der Funktion in einem std::string gespeichert

#include <iostream>
#include <string>
using namespace std;

typedef int (WINAPI * MessageBoxPtr)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
std::string Dll = "User32.dll";
std::string Function = "MessageBoxA";

int main(int argc, char** argv)
{
    MessageBoxPtr Message = (MessageBoxPtr) GetProcAddress(LoadLibraryA(Dll.c_str()),Function.c_str());
    if(Message != 0)
	Message(0,"Durch Funktionszeiger aufgerufen","Information",0);

    return 0;
}

Was bleibt noch über? Naja es heißt ja „WinAPI-Crypting„, also sollten wir auch den Funktionsnamen und den Namen der Dll verschlüsseln und zur Laufzeit übersetzen. Da ich hier nicht näher auf verschiedene Verschlüsselungsalgorithmen eingehen möchte, verschiebe ich einfach jeden Buchstaben um eine Stelle in der Ascii-Tabelle. So erhalte ich für „User32.dll“ „Vtfs43/emm“ und für „MessageBoxA“ „NfttbhfCpyB“.

Der gesamte Code sieht nun wie folgt aus

#include <iostream>
#include <string>
using namespace std;

typedef int (WINAPI * MessageBoxPtr)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
std::string Dll = "Vtfs43/emm";
std::string Function = "NfttbhfCpyB";

void decrypt_strings();

int main(int argc, char** argv)
{
    decrypt_strings();
    MessageBoxPtr Message = (MessageBoxPtr) GetProcAddress(LoadLibraryA(Dll.c_str()),Function.c_str());
    Message(0,"Durch Funktionszeiger aufgerufen","Information",0);
    return 0;
}

void decrypt_strings()
{
    unsigned int i;
    for(i=0;i<Dll.length();i++)
    {
        Dll[i] = (char) (((int) Dll[i])-1);
    }

    for(i=0;i<Function.length();i++)
    {
        Function[i] = (char) (((int) Function[i])-1);
    }
}

Abschließende Worte

Ich hoffe ihr hattet, trotz des schlechten Themas, Spaß beim Lesen und der ein oder andere Leser hat etwas neues erfahren.

mfg
TgZero

]]>
https://technik.blogbasis.net/winapi-crypting-08-10-2013/feed 0