…of digital waterhttp://ofdigitalwater.postach.io/feed.xml2021-06-27T07:29:35.767000ZWerkzeugFetch German lawshttps://ofdigitalwater.postach.io/post/fetch-german-laws2021-06-27T07:29:35.767000Z2021-06-26T20:17:24ZWincent Balin<p>In this part of series, I will describe, how to fetch German law texts from https://www.gesetze-im-internet.de.</p>
<h2>Four formats</h2>
<p>The (federal) laws in Germany are published by the <a href="https://www.bmjv.de/">Federal Ministry of Justice and Consumer Protection</a> on https://www.gesetze-im-internet.de. There are also land (i.e. state) laws, published <a href="http://www.justiz.de/onlinedienste/bundesundlandesrecht/index.php">here</a>, administrative regulations, published <a href="http://www.verwaltungsvorschriften-im-internet.de/">here</a>, and many more laws, but for the sake of simplicity we will use the texts of federal laws only.</p>
<p>As stated in the <a href="http://www.gesetze-im-internet.de/hinweise.html">notes page</a>, there are four formats available:</p>
<ul>
<li>HTML (which you can view in browser)</li>
<li>PDF (most suitable for archive or for printed documents)</li>
<li>EPUB (for e-book readers)</li>
<li>XML (original format, which can be converted easily to other formats)</li>
</ul>
<p>The format of the XML representation is defined by <a href="http://www.gesetze-im-internet.de/dtd/1.01/gii-norm.dtd">this DTD</a>, which will become very helpful in the next part of this series.</p>
<p>As also stated on the mentioned above notes page, the index XML documents is available at http://www.gesetze-im-internet.de/gii-toc.xml. This index links to XML documents, packed into ZIP archives, all of them having the same name <code>xml.zip</code>.</p>
<h2>The choice of the format</h2>
<p>From the four available formats, we need the one, which represents the resulting text with the least markup. The requirement comes from the need to generate a future law text with as little markup as possible.</p>
<p>This requirement, of course, eliminates the PDF format, because it is adapted to the printed media. While the HTML format could be converted to text, for example with the veritable <a href="http://www.aaronsw.com/2002/html2text/">html2text</a>, the contents of law texts are split between small sections, hence complicating the conversion. The conversion of the EPUB format to text is difficult to customise, at least in comparison to XML. Finally, for XML format, there is already a converter to plain text, described in <a href="https://ofdigitalwater.postach.io/post/convert-german-laws-from-xml-to-text">another post</a>.</p>
<p>So we need the documents in XML format.</p>
<h2>How to parse HTML with batteries included</h2>
<p>Even before <a href="https://www.crummy.com/software/BeautifulSoup/">Beautiful Soup</a>, it was possible to parse HTML data using the class <code>HTMLParser</code> from the package <code>html.parser</code>, documented <a href="https://docs.python.org/3/library/html.parser.html#html.parser.HTMLParser">here</a>.</p>
<p>Also, even before <a href="https://docs.python-requests.org/">requests</a>, it was possible to fetch data over HTTP with the functions <code>urlopen</code> and <code>urlretrieve</code> from the package <code>urllib.request</code>, documented <a href="https://docs.python.org/3/library/urllib.request.html#urllib.request.urlopen">here</a> and <a href="https://docs.python.org/3/library/urllib.request.html#urllib.request.urlretrieve">here</a>.</p>
<p>Should you ask yourself at this point, why do I overlook two very nice and tried Python packages, please read the list under <strong>First things first</strong> in <a href="https://ofdigitalwater.postach.io/post/generate-german-laws">this article</a>.</p>
<p>To parse HTML with the <code>HTMLParser</code> class, you simply create a subclass from it. Then, depending on what you need to get from HTML data, you implement the <code>handle_*</code> methods. For example, to parse links from the https://www.gesetze-im-internet.de front page, you need the following code:</p>
<p><script src="https://gist.github.com/wincentbalin/7c3cda669094ef830c5f93decb145dd5.js?file=frontpage.py"></script></p>
<h2>Collecting all XML documents</h2>
<p>While, as mentioned above, there is a list of XML documents <a href="http://www.gesetze-im-internet.de/gii-toc.xml">here</a>, we will try to collect URLs of all XML documents from the list of current documents at http://www.gesetze-im-internet.de/aktuell.html.</p>
<p>The parser implemented for this page is similar to the previous example. As the current documents are grouped by the first character into separate lists, this parser collects the links to these lists:</p>
<p><script src="https://gist.github.com/wincentbalin/7c3cda669094ef830c5f93decb145dd5.js?file=aktuellparser.py"></script></p>
<p>As all links to document lists are stored in the variable <code>partial_list_urls</code>, we must add another parser to fetch the links to XML documents. This parser also stores law names.</p>
<p><script src="https://gist.github.com/wincentbalin/7c3cda669094ef830c5f93decb145dd5.js?file=teillisteparser.py"></script></p>
<h2>Complete fetch code</h2>
<p>If we combine the two examples, and add some error handling and some <code>urlretrieve</code> action as well, we get this:</p>
<p><script src="https://gist.github.com/wincentbalin/7c3cda669094ef830c5f93decb145dd5.js?file=fetch.py"></script></p>
<p>After executing this code, we get 6518 ZIP files into the cache directory.</p>
<h2>Next step</h2>
<p>In the next step, we will build the text corpus from all the law texts fetched.</p>
<p>Stay tuned!</p>Generate German lawshttps://ofdigitalwater.postach.io/post/generate-german-laws2021-06-26T22:29:02.623000Z2021-06-26T19:17:30ZWincent Balin<p>In this series, I am going to describe, how to build a generator of German laws.</p>
<p><strong>First things first:</strong></p>
<ol>
<li>I am doing this for my own amusement.</li>
<li>Because of <strong>1.</strong>, I will not necessarily seek simple ways to do things.</li>
<li>You will most probably facepalm repeatedly reading the articles from this series.</li>
<li>Given enough time, you will learn to enjoy <strong>3.</strong></li>
</ol>
<h2>The goal</h2>
<p>… consists of four parts:</p>
<ol>
<li>Fetch German laws from https://www.gesetze-im-internet.de</li>
<li>Build text corpus from the downloaded laws</li>
<li>Train a char-RNN with the text corpus</li>
<li>Create an easy to use German law generator</li>
</ol>
<p>The prototype for XML conversion was done in the <a href="https://ofdigitalwater.postach.io/post/convert-german-laws-from-xml-to-text">previous article</a> on this blog.</p>
<h2>Next step</h2>
<p>In the next post, we are going to create the code that fetches all the law texts.</p>
<p>Stay tuned!</p>Convert German laws from XML to texthttps://ofdigitalwater.postach.io/post/convert-german-laws-from-xml-to-text2021-06-26T01:50:27.899000Z2021-06-26T01:33:14ZWincent Balin<p>For a small project, I needed to convert German laws, found at https://www.gesetze-im-internet.de/, from XML format to text format.</p>
<p>The XML format is described <a href="https://www.gesetze-im-internet.de/hinweise.html">here</a> and is defined by <a href="https://www.gesetze-im-internet.de/dtd/1.01/gii-norm.dtd">this DTD file</a>.</p>
<p>The source code in the following XSL file is pretty straight-forward. Only adding newlines and indenting definition lists posed an additional challenge.</p>
<p><script src="https://gist.github.com/wincentbalin/bd62c3a8e5a82b42d6c29124acaf352b.js"></script></p>How to import large Plaso file into Timesketch in Dockerhttps://ofdigitalwater.postach.io/post/how-to-import-large-plaso-file-into-timesketch-in-docker2020-03-13T10:36:35.479000Z2020-03-12T20:20:22ZWincent Balin<p>Sometimes <a href="https://github.com/google/timesketch/">Timesketch</a>, being run in <a href="https://www.docker.com/">Docker</a>, hiccups when importing a <a href="https://github.com/log2timeline/plaso">Plaso</a> file too large, like in the <a href="https://github.com/google/timesketch/issues/1060">issue #1060</a>. You can still upload the file using this shell script:</p>
<pre><code class="sh">#!/bin/sh
#
# Run this script with timesketch_import_plaso.sh plaso_file [timesketch_container]
if [ $# -eq 0 ]
then
echo Run this script with $0 plaso_file [timesketch_container]
exit 1
fi
DOCKER_PATH="/tmp/`basename $1`"
TIMELINE="`echo $1 | sed -e 's/\.[^.]*$//'`"
CONTAINER=docker_timesketch_1
if [ ! -z "$2" ]
then
CONTAINER=$2
fi
docker cp "$1" "$CONTAINER:/tmp"
docker exec -it "$CONTAINER" psort.py -o timesketch --name "$TIMELINE" "$DOCKER_PATH"
docker exec -it "$CONTAINER" rm "$DOCKER_PATH"
</code></pre>Links to Windows SFU and SUAhttps://ofdigitalwater.postach.io/post/links-to-windows-sfu-and-sua2019-10-04T22:24:13.083000Z2019-10-04T21:54:16ZWincent Balin<p>Should you want to use <a href="https://en.wikipedia.org/wiki/Windows_Services_for_UNIX">Microsoft Windows Services for UNIX</a> (SFU) within Windows XP or Windows Server 2003, you need SFU 3.5, which you will currently (October 2019) find either <a href="https://archive.org/download/cdrom-services-unix-3.5-microsoft-2004">in the Internet Archive</a> as an ISO image or <a href="https://www.microsoft.com/en-us/download/details.aspx?id=20983">at Microsoft</a> as setup executables.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Windows_Services_for_UNIX#Legacy">Subsystem for UNIX-Based Applications</a> (SUA), which works with Windows 7, is also available <a href="https://www.microsoft.com/en-us/download/details.aspx?id=2391">at Microsoft</a>, as well as <a href="https://www.microsoft.com/en-us/download/details.aspx?id=23754">SUA for Windows Vista</a>.</p>If you want to run Docker on local Linux boxhttps://ofdigitalwater.postach.io/post/if-you-want-to-run-docker-on-local-linux-box2019-10-04T12:39:46.993000Z2019-10-04T11:47:16ZWincent Balin<p>If you would like to run <a href="https://www.docker.com/">Docker</a> on a Linux box in your LAN, and you already configured the Linux box hostname as <em>computer1</em> and a user account there as <em>me</em>, and your current Docker environment is <a href="https://docs.docker.com/toolbox/toolbox_install_windows/">Docker Toolbox on Windows</a> together with <a href="https://docs.docker.com/machine/">docker-machine</a>, perform the following steps:</p>
<ol>
<li>Add user <em>me</em> to the group <em>sudo</em> on your future Docker host: <code>usermod -a -G sudo me</code></li>
<li>Remove password prompt when running <code>sudo</code> (as described <a href="https://kofler.info/sudo-ohne-passwort/">here</a>):<br />
Replace <code>%sudo ALL=(ALL) ALL</code> with <code>%sudo ALL=(ALL) NOPASSWD: ALL</code></li>
<li>Run this command in your current Docker environment to install Docker on your future Docker host: <code>docker-machine create --driver generic --generic-ip-address computer1 --generic-engine-port 2375 --generic-ssh-user me computer1</code>. The last part is the name of the configuration in your current Docker environment.</li>
<li>Activate the configuration in your current Docker environment: <code>eval $("C:\Program Files\Docker Toolbox\docker-machine.exe" env computer1)</code></li>
<li>Reverse step 2 and, if needed, also step 1</li>
</ol>
<p>Then you are ready to use Docker on your <em>computer1</em> box.</p>
<p>Perform step 4 to activate this configuration again.</p>Starting with Intel Galileohttps://ofdigitalwater.postach.io/post/starting-with-intel-galileo2019-10-01T19:16:47.905000Z2019-10-01T15:59:59ZWincent Balin<p><a href="https://www.intel.com/content/www/us/en/support/products/78906/boards-and-kits/intel-galileo-boards.html">Intel Galileo</a> is a Intel Pentium-based platform, which is supported by Arduino IDE. It runs Linux, and it is possible to install a PCI-Express card (most often the Intel Centrino Wi-Fi board gets installed).</p>
<p><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/e8b0153c-6cfd-4b5c-a5ea-ed05765823a6/671d3e4a-58c0-4bd7-9f5d-0bfb34533eb1.png" /></p>
<p>It is also one of the <a href="https://www.arduino.cc/en/ArduinoCertified/IntelGalileo">Arduino-certified</a> platforms. The configuration in Arduino IDE consists in installing the <strong>Intel i586 boards</strong> platform in the board manager. The firmware is uploaded though the <em>USB CLIENT</em> port as usual.</p>
<p>If you want to communicate with Linux on Galileo directly, you need the <a href="https://www.intel.com/content/www/us/en/support/articles/000006343/boards-and-kits/intel-galileo-boards.html">cable adapter</a>; if you would like to solder one by yourself, the pinout is available <a href="https://www.pccables.com/Products/Intel-Galileo-Board-Serial-Cable-DB9-F-to-3.5mm.html">here</a>. Connect to the board using serial port with 115200 bps, and voilà!</p>
<p><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/e8b0153c-6cfd-4b5c-a5ea-ed05765823a6/245d5662-065b-4f22-875c-8a9e169240ac.png" /></p>Office in Vagrant VMhttps://ofdigitalwater.postach.io/post/office-in-vagrant-vm2019-08-11T19:19:27.468000Z2019-07-16T16:48:25ZWincent Balin<p>I wanted to use office software in a VM, while being able to edit files on the host machine. Usually, people create a VM in <a href="https://www.virtualbox.org/">VirtualBox</a> and map the host directory into this VM using <a href="https://www.virtualbox.org/manual/ch04.html#sharedfolders">shared folders</a>. But, because it is a long process, I decided to automate it using <a href="https://vagrantup.com">Vagrant</a>.</p>
<h1>TL;DR</h1>
<ol>
<li>Go to <a href="https://github.com/wincentbalin/VirtualOffice">this GitHub repository</a></li>
<li>Download <code>Vagrantfile</code> and place it into your documents directory</li>
<li>Open your favourite CLI and change into that directory</li>
<li>Run <code>vagrant up</code> to configure the VM and wait for a while</li>
<li>Run <code>vagrant rdp</code> and use <em>vagrant</em> as login and as password</li>
<li>Open LibreOffice and configure your personal data, so the documents with data fields can set them to appropriate values</li>
<li>Edit your documents on the host system!</li>
</ol>
<h1>Design decisions</h1>
<p>The <code>Vagrantfile</code> must be placed into directory with documents you want to edit. Of course, I could add the default documents directory on the host OS, but I decided against it: first, it would create additional maintenance burden (especially if the syntax for default OS paths changes), and second, it would not work on systems, where the documents directory was moved to another location. So, for now, the entry for synchronised directory is</p>
<pre><code class="ruby">config.vm.synced_folder ".", "/home/vagrant/Documents", mount_options: ["dmode=775,fmode=664"]
</code></pre>
<p>The VM created by Vagrant is based on Ubuntu Bionic x64. The <code>Vagrantfile</code> installs the packages <code>xubuntu-desktop</code> and <code>libreoffice</code>. Then it also enables Remote Desktop connexions by installing <code>xrdp</code>, by starting it automatically as a service and by enabling port 3389. The forwarding to the port is configured with</p>
<pre><code class="ruby">config.vm.network "forwarded_port", guest: 3389, host: 33389, protocol: "tcp", auto_correct: true
</code></pre>
<p>The automatic start of XFCE session is enabled by adding <code>xfce4-session</code> to the file <code>.xsession</code>. Everything is run as the default Vagrant user <code>vagrant</code>.</p>Run IDLE (Python IDE) in virtual environmenthttps://ofdigitalwater.postach.io/post/run-idle-python-ide-in-virtual-environment2019-06-28T18:34:27.160000Z2019-06-28T11:41:08ZWincent Balin<p>Imagine: you are running software implemented in Python and there is a problem you would like to debug or edit away. The software resides in a virtual environment and apart from this virtual environment and a standard Python installation nothing else is installed (or is not permitted to be installed). What should you do?</p>
<p>You can run <a href="https://docs.python.org/3/library/idle.html">IDLE</a> within the activated virtual environment with this command:</p>
<pre><code class="shell">python -m idlelib.idle
</code></pre>
<p>This command opens the starting window of IDLE with Python prompt. From there you can open the file you would like to edit.</p>
<p>But what if you would open the Python file at once? Use this command then:</p>
<pre><code class="shell">python -m idlelib.idle filename
</code></pre>
<p>While IDLE does not have all niceties of PyCharm, it is better than Notepad.exe, is almost always installed and has debugging capabilities. You might even enjoy it.</p>
<p>Source: <a href="https://gist.github.com/wincentbalin/411d89dea8a0a017eb4068cf5a007b2e">Run IDLE from a batch file</a></p>Python shebanghttps://ofdigitalwater.postach.io/post/python-shebang2019-06-15T11:25:00.592000Z2019-06-15T11:08:02ZWincent Balin<p>Currently, in the interregnum where Python 2 and Python 3 may co-exist on the same system, the <a href="https://www.python.org/dev/peps/pep-0394/#recommendation">PEP 0394 recommendations</a> for the <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">shebang</a> line in Python programs run in short like this:</p>
<ol>
<li>Use <code>#!/usr/bin/env</code> before Python interpreter</li>
<li>Use <code>#!/usr/bin/env python</code> <em>only</em> for programs that work with <em>both</em> Python 2 and Python 3</li>
<li>If your program runs with Python 3 only, replace <code>python</code> in the previous line with <code>python3</code></li>
<li>Else, for Python 2-based programs, replace <code>python</code> with <code>python2</code></li>
</ol>How to keep your forked GitHub repository up to datehttps://ofdigitalwater.postach.io/post/how-to-keep-your-forked-github-repository-up-to-date2019-06-15T11:24:59.986000Z2019-06-02T10:59:55ZWincent Balin<h3>1. Clone your fork:</h3>
<pre><code class="sh">git clone git@github.com:YOUR-USERNAME/YOUR-FORKED-REPO.git
</code></pre>
<h3>2. Add remote from original repository to your forked repository:</h3>
<pre><code class="sh">cd into/cloned/fork-repo
git remote add upstream git://github.com/ORIGINAL-DEV-USERNAME/REPO-YOU-FORKED-FROM.git
git fetch upstream
</code></pre>
<h3>3. Updating your fork from original repo to keep up with their changes:</h3>
<pre><code class="sh">git pull upstream master
</code></pre>
<p>Source: <a href="https://gist.github.com/KINGSABRI/b7a07fee84affc7d041acc48e9cb4a7e">this gist</a></p>Print in Python without newlinehttps://ofdigitalwater.postach.io/post/print-in-python-without-newline2019-06-15T11:24:59.605000Z2019-05-05T14:42:17ZWincent Balin<p>If you want to print a string in Python without newline at the end, do it like <a href="https://stackoverflow.com/questions/493386/how-to-print-without-newline-or-space">this</a>:</p>
<pre><code class="python"># ... and if you are in Python 2: from __future__ import print_function
print('.', end='')
</code></pre>Bootstrap does not use complete jQueryhttps://ofdigitalwater.postach.io/post/bootstrap-does-not-use-complete-jquery2019-05-05T12:12:04.339000Z2019-05-05T11:50:34ZWincent Balin<p>Should you want to use <a href="https://getbootstrap.com/">Bootstrap framework</a>, you will also include <a href="https://jquery.com/">jQuery library</a>, for example:</p>
<pre><code class="html"><script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</code></pre>
<p>If you pay attention to the filename of jQuery included, you will see that this is the <a href="https://stackoverflow.com/questions/35424053/what-are-the-differences-between-normal-and-slim-package-of-jquery"><em>slimmed</em></a> version of the library. For example, it does not have <code>$.get()</code> function.</p>
<p>Should you want to perform AJAX, or use other functions not contained in the slimmed version, include the full jQuery instead, in the above case:</p>
<pre><code class="html"><script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
</code></pre>Create GitHub ribbonhttps://ofdigitalwater.postach.io/post/create-github-ribbon2019-06-15T11:27:36.491000Z2019-05-05T01:00:10ZWincent Balin<p>Should be in need of a HTML code for a GitHub ribbon, go <a href="https://azu.github.io/github-ribbon-generator/">there</a>.</p>If Debian says "The following packages have been kept back:"https://ofdigitalwater.postach.io/post/if-debian-says-the-following-packages-have-been-kept-back2019-06-15T11:24:57.201000Z2019-05-04T22:01:22ZWincent Balin<p>According to <a href="https://askubuntu.com/questions/601/the-following-packages-have-been-kept-back-why-and-how-do-i-solve-it">this askubuntu.com question</a>, if your Debian-based Linux tells you <code>The following packages have been kept back:</code> while upgrading, you might do this:</p>
<ol>
<li>Run <code>sudo apt-get --with-new-pkgs upgrade</code></li>
<li>Run <code>sudo apt-get install <list of packages kept back></code></li>
<li>(If nothing else helps, run <code>sudo apt-get dist-upgrade</code>, but beware of automatic package removals!)</li>
</ol>Replacing text using regex groups in VSCodehttps://ofdigitalwater.postach.io/post/replacing-text-using-regex-groups-in-vscode2019-05-05T00:07:51.688000Z2019-05-04T14:22:23ZWincent Balin<p>You can save much time by using regular expressions in the <em>Replace</em> dialog of <em>Visual Studio Code</em> editor. The captured groups can be recalled as <code>$1</code>, <code>$2</code> etc in the replacement field of the same dialog.</p>Vagrant environment for OpenGRMhttps://ofdigitalwater.postach.io/post/vagrant-environment-for-opengrm2019-05-01T18:32:03.427000Z2019-05-01T18:12:47ZWincent Balin<p>Recently I uploaded my <a href="https://vagrantup.com/">Vagrant</a> environment for <a href="http://www.opengrm.org">OpenGRM</a> to the <a href="https://github.com/wincentbalin/opengrm-vagrant">GitHub repository</a>. The provision script, <a href="https://github.com/wincentbalin/opengrm-vagrant/blob/master/install-opengrm.sh">install-opengrm.sh</a>, should install OpenFST/OpenGRM on any Linux computer it runs. Should you decide to run the provision script by hand, consult the <a href="https://github.com/wincentbalin/opengrm-vagrant/blob/master/Vagrantfile">Vagrantfile</a> to see the required software packages.</p>
<p>The list of OpenFST/OpenGRM projects installed:</p>
<ul>
<li><a href="http://www.openfst.org">OpenFST</a></li>
<li><a href="http://www.openfst.org/twiki/bin/view/Contrib/FstContrib">OpenFST Baum-Welch library</a></li>
<li><a href="http://www.openfst.org/twiki/bin/view/Contrib/FstContrib">OpenFST categorial semi-ring</a></li>
<li><a href="http://www.opengrm.org/twiki/bin/view/GRM/NGramLibrary">OpenGRM NGram library</a></li>
<li><a href="http://www.opengrm.org/twiki/bin/view/GRM/Thrax">OpenGRM Thrax grammar compiler</a></li>
<li><a href="http://www.opengrm.org/twiki/bin/view/GRM/Pynini">OpenGRM Pynini grammar compiler</a></li>
<li><a href="http://www.opengrm.org/twiki/bin/view/GRM/SFstLibrary">OpenGRM SFst library</a></li>
</ul>
<p>The versions of the packages installed are at the head of the provision script.</p>
<p>The software comes licensed under the <em>Apache License 2.0</em>.</p>If Gmail says "Our system has detected that this message does not meet IPv6 sending guidelines regarding PTR records"https://ofdigitalwater.postach.io/post/if-gmail-says-our-system-has-detected-that-this-message-does-not-meet-ipv6-sending-guidelines-regarding-ptr-records2019-05-01T18:02:54.351000Z2019-04-28T09:36:57ZWincent Balin<p>Essentially, <a href="https://mail.google.com/">Google Mail</a>'s SMTP server tells you that either the <em>PTR record with IPv6 address</em> of your SMTP server does not exist or this record does not match your server.</p>
<h1>The solution</h1>
<ol>
<li>Look at the DNS configuration of your SMTP server.</li>
<li>If it does not have a <em>PTR record</em> with the <em>IPv6 address</em> of that server, add it.</li>
<li>If your configuration does not allow adding PTR records, disable sending over <em>IPv6</em> in your SMTP configuration. For Postfix, ensure that the parameter <code>inet_protocols</code> (for example, in the file <code>/etc/postfix/main.cf</code>) looks like <code>inet_protocols = ipv4</code>, i.e. <em>without</em> <code>ipv6</code>.</li>
</ol>
<h1>Sources</h1>
<ul>
<li><a href="https://support.plesk.com/hc/en-us/articles/213936285-Unable-to-send-an-email-to-Gmail-Our-system-has-detected-that-this-message-does-not-meet-IPv6-sending-guidelines-regarding-PTR-records">https://support.plesk.com/hc/en-us/articles/213936285-Unable-to-send-an-email-to-Gmail-Our-system-has-detected-that-this-message-does-not-meet-IPv6-sending-guidelines-regarding-PTR-records</a></li>
<li><a href="https://support.plesk.com/hc/en-us/articles/213388269-Unable-to-send-mail-using-STARTTLS-authentication-4-7-0-TLS-not-available-due-to-local-problem">https://support.plesk.com/hc/en-us/articles/213388269-Unable-to-send-mail-using-STARTTLS-authentication-4-7-0-TLS-not-available-due-to-local-problem</a></li>
<li><a href="https://blog.kruyt.org/postfix-and-tls-encryption/">https://blog.kruyt.org/postfix-and-tls-encryption/</a></li>
</ul>Metaphors of chess and backgammonhttps://ofdigitalwater.postach.io/post/metaphors-of-chess-and-backgammon2019-04-27T17:56:56.979000Z2019-04-27T17:52:07ZWincent Balin<div>The game of chess is a good metaphor of an environment with openly visible rules. The game of backgammon is a good metaphor of an environment without, as the randomness of dices rolled functions as an abstraction of hidden rules.</div>
<div><br/></div>
Got a book: "Complete Babylonian"https://ofdigitalwater.postach.io/post/got-a-book-complete-babylonian2019-06-15T11:29:15.739000Z2019-02-20T16:01:28ZWincent Balin<div><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/bd62e569-c5eb-4846-908d-0b568596efb9/59c9c606-a1ec-48cd-b06c-388f5ece2886.jpg" width="2448"/></div>
<div><br/></div>
CouchDB views observationhttps://ofdigitalwater.postach.io/post/couchdb-views-observation2019-02-19T21:44:37.478000Z2019-02-19T19:00:55ZWincent Balin<blockquote>
<p>CouchDB views are more like <code>CREATE INDEX</code> than <code>SELECT</code>: <a href="https://stackoverflow.com/a/9237735">https://stackoverflow.com/a/9237735</a></p>
</blockquote>Static netcat .exe fileshttps://ofdigitalwater.postach.io/post/static-netcat-exe-files2019-02-03T13:56:16.096000Z2019-02-03T11:17:35ZWincent Balin<p>Today we are going to create static <code>.exe</code> binaries for <a href="http://nc110.sourceforge.net/">netcat</a>.</p>
<p>While there are many <a href="https://en.wikipedia.org/wiki/Netcat#Ports_and_reimplementations">ports and reimplementations of netcat</a>, we are going to stick with <code>win32</code> ports for <a href="https://github.com/ReneNyffenegger/netcat">netcat 1.11</a> or <a href="https://eternallybored.org/misc/netcat/">netcat 1.12</a> (the latter one enables sending <code>CRLF</code> line endings instead of <code>CR</code> using command line option <code>-c</code>).</p>
<p>We will use <a href="https://mxe.cc">MXE</a> as our cross-compilation environment. Compile the <code>cc</code> package as described in the <a href="https://mxe.cc/#tutorial">tutorial</a>. Add the directory with cross-compilers to your <code>PATH</code>.</p>
<p>Then download and unpack the source from the <code>win32</code> ports above and issue the following commands:</p>
<pre><code>i686-w64-mingw32.static-gcc -DNDEBUG -DWIN32 -D_CONSOLE -DTELNET -DGAPING_SECURITY_HOLE getopt.c doexec.c netcat.c -O2 -s -static -lkernel32 -luser32 -lwsock32 -lwinmm -o nc.exe
</code></pre>
<p>and</p>
<pre><code>x86_64-w64-mingw32.static-gcc -DNDEBUG -DWIN32 -D_CONSOLE -DTELNET -DGAPING_SECURITY_HOLE getopt.c doexec.c netcat.c -O2 -s -static -lkernel32 -luser32 -lwsock32 -lwinmm -o nc64.exe
</code></pre>
<p>to compile the 32-bit and 64-bit version respectively.</p>
<p>I compiled netcat 1.12 for you and placed it into a <a href="https://www.dropbox.com/sh/p55p891k15yisbg/AABtTEKNjMTGgYCDN26vNFG-a">Dropbox folder</a>.</p>
<p>If you decide to use them, here are the MD5 checksums:</p>
<pre><code>f630164e41932360440f43602f670d21 nc64.exe
bc3029d3e79265f9ab2e906009adb196 nc.exe
</code></pre>
<p>Here is the list with the netcat tutorials:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Netcat">https://en.wikipedia.org/wiki/Netcat</a></li>
<li><a href="http://nc110.sourceforge.net/">http://nc110.sourceforge.net/</a></li>
<li><a href="https://www.heise.de/select/ix/2017/11/1509815804306324">https://www.heise.de/select/ix/2017/11/1509815804306324</a> (in German)</li>
</ul>Cheat sheet for Kindle Terminalhttps://ofdigitalwater.postach.io/post/cheat-sheet-for-kindle-terminal2019-01-24T23:31:12.310000Z2019-01-24T17:45:00ZWincent Balin<div>If you plan to run <a href="https://www.turnkeylinux.org/blog/kindle-root">Linux on Kindle</a>, using <a href="https://www.mobileread.com/forums/showthread.php?t=154500">this terminal emulator</a> with Kindle Keyboard, I drew up a cheat sheet for you:</div>
<div><br clear="none"/></div>
<div><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/69137ac9-b098-4ca2-8d34-d817d1c09047/3773f613-e36b-4dcd-b5b5-a745d53ad875.jpg" width="395"/></div>
<div><br clear="none"/></div>
<div><br/></div>
<div><br/></div>
How to convert a batch of wav file to mp3 fileshttps://ofdigitalwater.postach.io/post/how-to-convert-a-batch-of-wav-file-to-mp3-files2019-01-20T20:28:04.597000Z2019-01-19T10:59:23ZWincent Balin<p>If you do not want to convert <code>.wav</code> files to MP3 format by hand and you have only Windows prompt on your hands, together with a <code>ffmpeg.exe</code> (look <a href="https://ffmpeg.zeranoe.com/builds/win64/static/">here</a>), the command to run is</p>
<pre><code>for %f in (*.wav) do ( ffmpeg -i "%f" -q:a 2 "%~nf.mp3" )
</code></pre>
<p>The parameter <code>-q:a 2</code> stands for <em>variable bitrate</em>; it is a standard FFMPEG parameter. You may use other FFMPEG parameters as well.</p>
<p>Look <a href="https://stackoverflow.com/questions/39615/how-to-loop-through-files-matching-wildcard-in-batch-file">here</a> for further Windows command-line improvements. </p>Solving locale problem on USB armoryhttps://ofdigitalwater.postach.io/post/solving-locale-problem-on-usb-armory2019-01-14T20:59:15.310000Z2019-01-14T20:50:17ZWincent Balin<p>Should you encounter the error message</p>
<pre><code>need UTF-8 locale (LC_CTYPE) but have ANSI_X3.4-1968
</code></pre>
<p>for example, when running <code>tmux</code>, you should do following steps to solve the problem that causes it:</p>
<ol>
<li>uncomment the appropriate locale in the <code>/etc/locale.gen</code> file</li>
<li>run <code>locale-gen</code></li>
</ol>
<p>Voila!</p>Mode switcher for USB armoryhttps://ofdigitalwater.postach.io/post/mode-switcher-for-usb-armory2019-01-26T17:54:54.263000Z2019-01-14T20:17:17ZWincent Balin<p><a href="https://inversepath.com/usbarmory">USB armory</a> is a flash drive sized secure computing device with an ARM processor. You may purchase it with a micro-SD card, on which a Debian is preinstalled. The preinstalled configuration enables a network connection from the host device. But should you want a different network configuration, for example one sharing Internet connexion from the host computer (look at <a href="https://github.com/inversepath/usbarmory/wiki/Host-communication">these instructions</a>), you will need this script to do it without much editing:</p>
<p><script src="https://gist.github.com/wincentbalin/83749d46ea5aadec6c3dcfd3ff672d21.js"></script></p>
<p>The last configuration, <code>host</code>, was created for using with <a href="https://github.com/inversepath/usbarmory/wiki/Host-adapter">host adapter</a> and a wi-fi USB adapter (I used <a href="https://www.amazon.de/EDIMAX-EW-7811UN-Wireless-Adapter-IEEE802-11b/">this one</a>). After installing the packages <code>wireless-tools</code> and <code>realtek-firmware</code> and a little configuration in the file <code>/etc/network/interfaces</code>, it just worked. Of course, you will need to replace the strings <code>SSID_of_a_wifi_network</code> and <code>PASSWORD_of_a_wifi_network</code> with appropriate values to connect to your wi-fi network automatically; use <code>wpa_passphrase</code> to generate wi-fi password hashes.</p>Utility for removing duplicated files for Windowshttps://ofdigitalwater.postach.io/post/utility-for-removing-duplicated-files-for-windows2019-01-14T00:09:53.021000Z2019-01-13T00:10:43ZWincent Balin<p>If you would like to remove duplicated files working in Linux, you use <a href="https://github.com/adrianlopezroche/fdupes">fdupes</a> utility. But what alternatives do you have, if you are working in Windows?</p>
<p>Meet <a href="https://gallery.technet.microsoft.com/scriptcenter/Duplicate-File-Finder-and-78f40ae9">Duplicate File Finder and Remover</a> (by Winston McMiller). It works in PowerShell, which nowadays is installed almost everywhere.</p>Credentials for SanDisk Connect Wireless Stickhttps://ofdigitalwater.postach.io/post/credentials-for-sandisk-connect-wireless-stick2019-01-12T23:14:28.871000Z2019-01-12T23:06:00ZWincent Balin<p>If you would like to connect to <a href="https://www.amazon.de/SanDisk-16GB-Connect-Wireless-Stick/dp/B00ZCFYDLA/">SanDisk 16 GB Connect Wireless Stick</a> via external IP address, you will be asked for access authorisation. The credentials the stick wants are <strong>owner/<em>wi-fi password</em></strong></p>Print default values of CLI arguments in Pythonhttps://ofdigitalwater.postach.io/post/print-default-values-of-cli-arguments-in-python2019-01-09T15:29:12.368000Z2019-01-08T18:21:10ZWincent Balin<p>If you would like to print default values of command-line arguments and if you use the <code>argparse.ArgumentParser</code> class in your Python program, consider setting the <code>formatter_class</code> option to <code>argparse.ArgumentDefaultsHelpFormatter</code>.</p>
<p>Example code:</p>
<pre><code>argparser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__,
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
argparser.add_argument('-s', '--std', type=float, default=440.0, help='Standard value')
args = argparser.parse_args()
</code></pre>An old German folksonghttps://ofdigitalwater.postach.io/post/an-old-german-folksong2019-01-05T19:00:26.570000Z2018-12-31T12:34:20ZWincent Balin<div>And now something about ethnomusicology.</div>
<div><br/></div>
<div>Three years ago, I was at a party. At one point the host requested an old folk song, "Tief im Tannwald ein Vöglein...", and I liked it very much. After recording it, I set out to discover more about it.</div>
<div><br/></div>
<div>In recent times, this song is almost forgotten. I found the lyrics at <a href="http://www.chefkoch.de/forum/2,45,502609/Wer-kennt-dieses-Weihnachtslied.html">Chefkoch.de</a> and <a href="http://www.gutefrage.net/frage/altes-weihnachtslied-gesucht">GuteFrage.net</a>, neither of which specialises in folk songs (the first one is a cooking portal, the other one is generic question-and-answer portal). But the sheet music was nowhere to be found. So I recreated it from the recording in <a href="http://abcplus.sourceforge.net/">ABC notation</a> format. The lyrics were taken from the first link, all three verses; I do not like the third verse, as the first and the second are about whats happening outside, and the third verse suddenly pictures what is happening at home, which appears somewhat inconclusive. It would be interesting to hear, whether there are other German folk songs with similar structure of lyrics.</div>
<div><br/></div>
<div>Here are the results as an ABC score (the lines need be rewrapped) and an image from it:</div>
<div style="text-align: justify;"><br/></div><code><div>X:1</div>
<div>T:Tief im Tannwald ein Vöglein...</div>
<div>A:Oldenburger Münsterland</div>
<div>H:As sung by Mrs. M. Ostendorf and guests on 27.12.2015</div>
<div>O:German Volkslied</div>
<div>K:C</div>
<div>M:3/4</div>
<div>L:1/4</div>
<div>G/2G/2 | DDE | CC E/2G/2 | cBA | E2 G/2A/2 | EE G/2A/2 |</div>
<div>w: Tief im Tann- wald ein Vög-lein hat das Christ-kind er-schaut, dort wo zwi-schen Tan-nen-</div>
<div>w: Und die En-ge-lein pflük-ken all die Tannen-bäum-chen ab, und das Christ-kind blik-ket</div>
<div>w: Wenn die Ster-ne-lein blin-ken in der Hei-li-gen Nacht, wer-den all die Tan-nen-</div>
<div>EE C/2D/2 | E/2E/2 D C | D2 G/2A/2 | G/2A/2 G/2A/2 G/2A/2 | EE E/2C/2 |</div>
<div>w: wip-feln hell der Win-ter-him-mel blaut. Und das Christ-kind schüt-telt sei-ne Löck-chen klin-ge-</div>
<div>w: lä-chelnd auf die Flei-ßi-gen her-ab. Und die Eis-kri-stal-le klir-ren lei-se, klin-ge-</div>
<div>w: bäum-chen zu den Kin-der-lein ge-bracht. Oh wie ju-beln da die Kin-der-her-zen, klin-ge-</div>
<div>G2 E/2C/2 | G2 A/2B/2 | c/2c/2 B/2B/2 A/2A/2 | EE A/2G/2 | A/2G/2 A/2G/2 (c | c2) ||</div>
<div>w: lang, klin-ge-lang. Aus der Fer-ne tönt's wie Sil-ber-glöck-chen: Klin-ge-lin-ge-lin-ge-lang!_</div>
<div>w: lang, klin-ge-lang. Und die Tan-nen-wip-fel nik-ken wei-se: Klin-ge-lin-ge-lin-ge-lang!_</div>
<div>w: lang, klin-ge-lang. Bei dem Lich-ter-glanz der Weih-nachts-ker-zen, klin-ge-lin-ge-lin-ge-lang!_</div></code><div><br/></div>
<div><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/f4983fbe-b82c-4dd5-a45e-d8ad67b8f2c1/7a234382-96d0-4ebf-8b0f-39ebd4d0ddba.png" width="1208"/></en-media><br/></div>
<div><br/></div>
<div><br/></div>
<div><br/></div>
Key codes on AB Shutter 3https://ofdigitalwater.postach.io/post/key-codes-on-ab-shutter-32018-12-22T18:07:47.688000Z2018-12-22T06:48:07ZWincent Balin<div>AB Shutter 3 is a small remote shutter.</div>
<div><br/></div>
<div><img src="https://cdn-images.postach.io/fa097c2a-1c29-4702-93f4-ab4cf778aa39/9f9a0774-ce0b-497a-b8af-b5ab6f599998/422fceff-1db2-4745-b604-b388e351c1f1.jpg" width="159"/></div>
<div><br/></div>
<div>It connects to your handset as a Bluetooth keyboard. But which key codes does it send to the device?</div>
<div><br/></div>
<div>To answer this question, I simply connected the shutter to my Android device, started an editor and pressed the buttons.</div>
<div><br/></div>
<div>These are the results:</div>
<div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div><span style="font-weight: bold;">Button</span></div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><span style="font-weight: bold;">Key function</span></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>iOS</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>Volume Up</div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>Android</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>Enter + Volume Up</div></td></tr></tbody></table><div><br/></div></div><div>Be aware: it is possible, that there are some other key codes sent that went unnoticed.</div>
<div><br/></div>
New blogging platformhttps://ofdigitalwater.postach.io/post/new-blog-platform2018-10-11T23:39:49.592000Z2018-07-30T23:39:49ZWincent Balin<p>Hello again! I decided to move this blog to <a href="https://postach.io/">postach.io</a>. The pains of running blog using <a href="https://gohugo.io/">Hugo</a> were adequately presented in <a href="https://flameeyes.blog/2017/07/12/why-i-do-not-like-hugo/">this post</a> by Diego Pettenò. As much as him, I neither like providing comments through <a href="https://disqus.com">Disqus</a>, but, on other hand, I am getting most of my comments through <a href="https://twitter.com">Twitter</a> and <a href="https://facebook.com">Facebook</a> instead, so it does not matter that much. What I cared about more was the storage of (my own) images I use in my articles and how easy it is to use them. I tried <a href="https://flickr.com">Flickr</a> with Hugo before and, well, it was the breaking point. Here, this is how easy it is now:</p>
<p style="text-align: center">
<img src="https://cdn-images.postach.io/30ae6c26-48e4-4e90-8064-36448d6652de/138cbcf3-f631-4344-aea6-aee0e756dd2a/0979febb-12bc-4b40-8cbc-9b7b80381697.jpg" width="99"/>
</p>
<h2>How I chose my next blogging platform</h2>
<p>I used <a href="https://www.creativebloq.com/web-design/best-blogging-platforms-
121413634">this article</a> as a starting point. Markdown was a must, image storage had to be simplified and the comments management would be a nice feature. I made some notes about the candidates (an ellipsis "..." means it requires some consideration):</p>
<ul>
<li><a href="https://
svbtle.com">svbtle.com</a>: clean, Markdown, costs $, no comments</li>
<li><a href="https://postach.io">postach.io</a>: Evernote! Disqus..., Markdown, is re-editing without changing order of articles possible? no problem here, <a href="https://help.postach.io/post/frequently-asked-questions">note's creation time is the publishing time</a></li>
<li><a href="https://medium.com">Medium.com</a>: serious, clean, long posts...</li>
<li><a href="http://pen.io">Pen.io</a>: rather anonymous</li>
<li><a href="https://tumblr.com">Tumblr.com</a>: clean, short articles..., Markdown</li>
<li><a href="https://wordpress.com">Wordpress.com</a>: Classic, ad-free for $, comments, Markdown</li>
<li><a href="https://blogger.com">Blogger.com</a>: classic, too much advertisement</li>
</ul>
<p>I also briefly considered to run <a href="http://tiddlywiki.com">TiddlyWiki</a> as a blog, but this would mean both lack of indexing through Google, as TiddlyWiki is rendered by JavaScript, and also that each time the user would wish to read it he would have to download more than 2 MB (yes, I know, both issues can be mitigated by running TiddlyWiki with Node.js, but then I could edit it being online only).</p>
<p>As an active user of <a href="https://evernote.com">Evernote</a>, postach.io was a winner among candidates for the next blog platform. It seems to have everything I need without all the everyday handicaps (especially regarding image storage!!!) the static site generators bring with them.</p>
<p>The second best candidate, to my dismay, was Wordpress, the platform I went away from before. Indeed, would I care as much about the comments as the author of the post above, I would have gone there.</p>
<p>Third place is divided between Medium and Tumblr, which in my opinion appear to be complimentary: Medium specialises in long reads, whereas on Tumblr you mostly have images with one or two paragraphs of text. I alternate between these two kinds, so neither one is appealing. And then the issue with the comments... Whereas Disqus locks the commentator into itself, both Tumblr and Medium practice the same thing, and nobody seems to notice. I already have two lock-ins, which I described in the introduction, and I do not need more of the same, at least not yet.</p>
<h2>Conclusion</h2>
<p>So, <a href="https://postach.io">postach.io</a> it is! And for now, it seems to work as a charm.</p>No TiddlyWiki on Kindle 3https://ofdigitalwater.postach.io/post/no-tiddlywiki-on-kindle-32018-09-11T16:43:17.855000Z2018-07-23T19:27:31ZWincent Balin<p>Alas, opening <a href="https://tiddlywiki.com/">TiddlyWiki</a> on <a href="https://www.amazon.com/Kindle-Keyboard-Free-Wi-Fi-Display/dp/B004HZYA6E">Kindle 3</a> using the experimental built-in web browser results in empty page.</p>audiowaveform compilationhttps://ofdigitalwater.postach.io/post/audiowaveform-compilation2019-06-02T10:58:40.832000Z2018-03-07T18:50:18ZWincent Balin<p>or</p>
<h1>How I gave my code fixes to BBC</h1>
<h2>Introduction</h2>
<p>I am working on a larger project, wherein I needed to visualise audio waveforms. Surprisingly, there are not that many programs able to do this. Even the Swiss Army Knife for all things audio, <a href="http://sox.sourceforge.net/">SoX</a>, plots only spectrograms and no waveforms.</p>
<p>But, because I chose the JavaScript library <a href="https://github.com/bbc/peaks.js">Peaks.js</a> (developed at <a href="https://github.com/bbc">BBC</a>) to plot waveforms in browser, I quickly found out that there is a utility called <a href="https://github.com/bbc/audiowaveform">audiowaveform</a> from the same authors, which converts audio file to data files, which <a href="https://github.com/bbc/peaks.js">Peaks.js</a> uses as an input.</p>
<p>There was just one little problem: there were no Windows binaries for audiowaveform available, there was even a related <a href="https://github.com/bbc/audiowaveform/issues/23">GitHub issue</a>.</p>
<p>So I sat down and put some effort into making audiowaveform compile. I never liked <em>DLL hell</em>, so I aimed at producing static binaries, both 32-bit and 64-bit. My earlier efforts to compile static Windows binaries for tools like <code>tshark</code>, <code>make</code>, <code>sed</code> and <code>sox</code> helped here immensely.</p>
<p>Actually, I achieved what aimed at, on two different ways.</p>
<h2>First way of compilation</h2>
<p>The first way of compilation uses <a href="https://docker.com/">Docker</a>. The compilation tools are <a href="https://github.com/wincentbalin/compile-static-audiowaveform">here</a>. You can read more about the setup in the <a href="https://github.com/wincentbalin/compile-static-audiowaveform/blob/master/README.md">README.md</a> file.</p>
<p>In short: The <a href="https://github.com/wincentbalin/compile-static-audiowaveform/blob/master/Dockerfile">Dockerfile</a> compiles all dependencies (meaning: <em>iconv</em>, <em>zlib</em>, <em>libmad</em>, <em>libid3tag</em>, <em>libogg</em>, <em>libvorbis</em>, <em>flac</em>, <em>libsndfile</em>, <em>libpng</em>, <em>libimagequant</em>, <em>freetype2</em>, <em>expat</em>, <em>fontconfig</em>, <em>libgd</em> and parts of <em>boost</em>) as static MinGW libraries, and then compiles audiowaveform for Win32. Then the directories are cleaned and another binaries for Win64 are recompiled. All resulting binaries, as well as <code>.h</code> and <code>.a</code> files, are compressed to ZIP archives, as Windows can unpack them without using external tool, and copied to the host system using the <code>docker cp</code> command. Executing the script</p>
<pre><code class="sh">./compile_audiowaveform.sh
</code></pre>
<p>automates the whole process.</p>
<h2>Second way of compilation</h2>
<p>There is a MinGW cross-compilation environment for free libraries called <a href="http://mxe.cc">MXE</a>. It is simple (essentially, a single <code>Makefile</code>), well-maintained (<a href="https://github.com/mxe/mxe.git">here</a>) and contains all (mentioned previously) dependencies already, so it was a natural choice.</p>
<p>The script (as well as the patch) for compilation using MXE also reside in <a href="https://github.com/wincentbalin/compile-static-audiowaveform/">this</a> repository. Just copy both files to the machine with MXE and execute the script</p>
<pre><code class="sh">./compile_audiowaveform_mxe.sh
</code></pre>
<p>Specify the path of MXE in the environment variable <code>MXE</code> and the amount of parallel jobs in the variable <code>JOBS</code>. So, compile audiowaveform with dependencies using MXE in the directory <code>/opt/mxe</code> on a quad-core CPU with command</p>
<pre><code class="sh">MXE=/opt/mxe JOBS=4 ./compile_audiowaveform_mxe.sh
</code></pre>
<p>After a while (because MXE compiles all parts of <em>boost</em>, additionally to the required ones) you will have two static Windows binaries, <code>audiowaveform-win32.exe</code> and <code>audiowaveform-win64.exe</code>, in the same directory as the script.</p>
<h2>Results</h2>
<p>We have now two ways to compile <a href="https://github.com/bbc/audiowaveform">audiowaveform</a>: <a href="https://github.com/wincentbalin/compile-static-audiowaveform/blob/master/compile_audiowaveform.sh">through Docker</a> or <a href="https://github.com/wincentbalin/compile-static-audiowaveform/blob/master/compile_audiowaveform_mxe.sh">through MXE</a>. Both ways yield both Win32 and Win64 binaries.</p>
<p>The single compilation problem fixed was the difference between filename container types — <code>std::string</code> on POSIX and <code>std::wstring</code> on Windows. After testing both ways of compilation, I contacted the main developer of <a href="https://github.com/bbc/audiowaveform">audiowaveform</a>, <a href="https://github.com/chrisn">Chris Needham</a>, and asked him about merging my code into the main repository. His reaction was very affirming, hence I made a <a href="https://github.com/bbc/audiowaveform/pull/61">pull request</a>, and he merged it.</p>
<p>The <a href="https://www.bbc.co.uk/">BBC</a> has my code fixes. I am positively excited.</p>Cambridge Z88 Serial Connexionhttps://ofdigitalwater.postach.io/post/this-is-a-beginning-of-a-much-larger-project-for-now-i-will-just-concentrate-o2018-09-11T16:43:14.955000Z2018-02-21T18:03:46ZWincent Balin<p>This is a beginning of a much larger project. For now, I will just concentrate on making a serial connexion to <a href="https://en.wikipedia.org/wiki/Cambridge_Z88">Cambridge Z88</a> computer. If you are impatient, just scroll to the end of the article.</p>
<p>I must confess here that I have a certain corner of my heart reserved for portable computers with <a href="https://en.wikipedia.org/wiki/Z80">Z80</a> processor. It is the thought of the glimpse of the dream about digital nomad the authors of these machines had. Of course, the computers that survived that long do not support modern technologies, but let us not rush…</p>
<p>These are the specifications for both the Z88 serial cable (from the <em>Z88 User Manual</em>) and for the different serial connectors I found at home.</p>
<p><a data-flickr-embed="true" data-header="true" data-footer="true" href="
https://www.flickr.com/photos/159998713@N04/albums/72157696672489232
" title="Cambridge Z88 Serial Connexion Specifications"><img src="
https://farm2.staticflickr.com/1831/43097057824_8893346449.jpg
" width="500" height="500" alt="Cambridge Z88 Serial Connexion Specifications"></a><script async src="//
embedr.flickr.com/assets/client-code.js
" charset="utf-8"></script></p>
<p>At the end, I found the best specification in the <a href="https://cambridgez88.jira.com/wiki/spaces/ZP/pages/120887895/Z88+Serial+Cable">Z88 wiki</a>. I chose a RS232 extension cable, which has male connector on one end and the female one on another. The wires inside the connectors (and cable) are color-coded, so it was easy to find the wires belonging to the pins I needed. I resoldered the wires at the female connector.</p>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/wincentbalin/43097058024/" title="Resoldered female connector by wincent.balin, on Flickr"><img src="https://farm2.staticflickr.com/1835/43097058024_c40c8dfb4d_b.jpg" width="1024" height="576" alt="Resoldered female connector"></a><script async src="https://embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<p>Afterwards, I enclosed the connectors again and connected Z88 with my little laptop through a USB-to-serial adapter. Then I created a 9600 baud connection in my terminal program. This program is rather rudimentary (for example, it has no <em>local echo</em>), but it was sufficient for this simple task. And then I tested the connexion. You can watch the results in this video.</p>
<p><div class="responsive-embed embed-16by9"><iframe width="640" height="360" src="https://www.youtube.com/embed/A71V3u1iwIU?feature=oembed" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></div></p>Trying out Piano HAThttps://ofdigitalwater.postach.io/post/trying-out-piano-hat2018-09-11T16:43:21.357000Z2018-02-17T18:11:42ZWincent Balin<p><a href="https://shop.pimoroni.com/products/piano-hat">Piano HAT</a> is an add-on board with piano keyboard and a couple of switches for <a href="https://www.raspberrypi.org/">Raspberry Pi</a> single-board computer. Today I tried out Piano HAT on Raspberry Pi 3.</p>
<p><div class="responsive-embed embed-16by9"><iframe width="480" height="360" src="https://www.youtube.com/embed/LE88AnoQfOw?feature=oembed" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></div></p>
<p>The capacitive touch keyboard is reminiscent of <a href="touch-demo-drum-board">Touch Demo Drum Board</a>, but the platform is, of course, much more versatile.</p>Relaunchhttps://ofdigitalwater.postach.io/post/relaunch2018-09-11T16:43:21.458000Z2018-02-04T06:59:59ZWincent Balin<p>Hello, dear readers!</p>
<p>As you see, this blog has been relaunched. Now it is powered by <a href="http://gohugo.io/">Hugo</a> instead of <a href="http://wordpress.org/">Wordpress</a>, therefore it uses much less resources on server and can even be edited (and tested) offline.</p>
<p>The blog's appearance is <a href="http://github.com/nurlansu/hugo-sustain/">hugo-sustain</a> with <a href="http://github.com/wincentbalin/hugo-sustain/">minor updates</a>. The (pre-moderated) comments are provided by <a href="http://disqus.com">Disqus</a>.</p>
<p>The themes in this blog did not change — music technology, computing, programming experiments. I will publish older projects too, of which I have many.</p>
<p>In addition, short articles about interesting links and images will appear here from now on too.</p>
<p>Keep calm and read on!</p>Using make for automatic processinghttps://ofdigitalwater.postach.io/post/using-make-for-automatic-processing2018-09-11T16:43:15.551000Z2014-03-20T01:56:58ZWincent Balin<p>Recently, I needed to extract text from a PDF file. This PDF file was produced from scanned pages. To extract the pages back, I used command</p>
<pre><code>pdfimages file.pdf IMG
</code></pre>
<p>This stored the original scans in PBM-formatted image files. The files were named in the <code>IMG-XXX.pbm</code> pattern, with <code>XXX</code> starting at <code>000</code> and incrementing.</p>
<p>In the next step I converted raw <code>.pbm</code> files to the TIFF format, as <a href="https://github.com/tesseract-ocr">Tesseract OCR software</a> prefers this format. Doing so using <a href="http://imagemagick.org">ImageMagick</a> command <code>convert</code>, the images were additionally processed to remove spots and other mishaps. The format conversion and image processing command as whole was</p>
<pre><code>convert -verbose -colorspace gray -median 3x3 -resize 300% -blur 10 input.pbm output.tiff
</code></pre>
<p>As I repeatedly tried different image processing chains for multiple images at once, the execution time exceeded 1 minute. It occured to me, looking at the CPU load, that only one core has been used at a time. Surely the multi-process execution on a multi-core CPU would speed up every OCR run. But I was unsure at first, whether there is a simple process manager, which limits amount of concurrently running processes. Then I remembered about an old acquaintance, <a href="http://en.wikipedia.org/wiki/Make_%28software%29"><code>make</code></a>, or, precisely, <a href="https://www.gnu.org/software/make/">GNU <code>make</code></a>. The tool also resolves dependencies automatically, which helps scheduling of processes, additionally.</p>
<p>The only problem yet to solve was the lack of rules for translation, or, in <code>make</code> parlance, <em>pattern rules</em>, from the source image to the OCRed text. Luckily, years ago I used <code>make</code> to produce both printable and audible music scores from descriptions, written in <a href="http://en.wikipedia.org/wiki/ABC_notation">ABC notation</a>, automatically; therefore, I only had to read up the <a href="https://www.gnu.org/software/make/manual/make.html"><code>make</code> documentation</a> again. This is the result:</p>
<pre><code class="makefile">CONVERT = convert
IMFLAGS = -verbose -colorspace gray -median 3x3 -resize 300% -blur 10
TESSERACT = tesseract
RM = rm
SRCS = $(wildcard *.pbm)
INTERMEDIATES = ${SRCS:.pbm=.tiff}
RESULTS = ${SRCS:.pbm=.txt}
.PHONY: all clean
all: $(RESULTS)
.PRECIOUS: $(INTERMEDIATES)
clean:
$(RM) -f $(INTERMEDIATES) $(RESULTS)
%.tiff: %.pbm
$(CONVERT) $(IMFLAGS) $< $@
%.txt: %.tiff
$(TESSERACT) $< $(basename $@) -l deu
</code></pre>
<p>The commands <code>convert</code>, <code>tesseract</code> and <code>rm</code> are stored in variables <code>CONVERT</code>, <code>TESSERACT</code> and <code>RM</code> for being able to specify unusual locations of them. The variables <code>SRCS</code>, <code>INTERMEDIATES</code> and <code>RESULTS</code> contain file names. The declaration <code>.PHONY</code> instructs <code>make</code> to execute targets <code>all</code> and <code>clean</code> even when there are actual files names <code>all</code> or <code>clean</code>. The <code>.PRECIOUS</code> declaration instructs <code>make</code> to preserve intermediate files. Line groups, starting in the form of <code>%to: %from</code>, are pattern rules (rules for translation). <code>$<</code> and <code>$@</code> mean source and target file respectively.</p>
<p>Run with <code>make -j number</code>, where <code>number</code> amounts either to the number of cores or the number of threads in the CPU. On AMD CPU with 4 cores, I used <code>make -j 4</code>.</p>
<p>Using <code>make</code>, which is available for any off-the-shelf OS, you are able to speed up lengthy processing on multi-core systems. Also, <code>make</code> ensures seamless translations between different stages of processing chain.</p>
<p>Which leads to the question: where do you use <code>make</code>, aside from everyday source code compilation?</p>Using pcal to create monthly calendars in landscape formathttps://ofdigitalwater.postach.io/post/using-pcal-to-create-monthly-calendars-in-landscape-format2018-09-11T16:43:16.260000Z2013-07-08T00:11:09ZWincent Balin<p>Would you like to have a monthly calendar, printed using DIN A4 landscape format, like <a href="https://wincent.balin.at/files/june.pdf">this one</a>?</p>
<p>If you would, there is a utility for creating such calendars, called <code>pcal</code>. If your preferred operating system is an incarnation of Windows, you may download executables from <a href="http://pcal.sourceforge.net/"><br />
http://pcal.sourceforge.net/<br />
</a> and run them on the command line with the options provided below. If your operating system of choice is Linux, most, if not all, major distributions will provide a corresponding package (in Ubuntu, just run <code>sudo apt-get install pcal</code>).</p>
<p>To create the calendar above, I simply ran these commands:</p>
<pre><code class="batch">pcal -o june.ps -P a4 -M -F 1 -E
ps2pdf june.ps
</code></pre>
<p>The first command, which runs <code>pcal</code> to produce the aforementioned calendar in Postscript format, uses a lot of options, which shall be explained:</p>
<ul>
<li><code>-o june.ps</code> This option lets the program write calendar into the file <code>june.ps</code>.</li>
<li><code>-P a4</code> specifies the paper size of DIN A4.</li>
<li><code>-M</code> adds pictograms of Moon phases to the calendar.</li>
<li><code>-F 1</code> sets Monday as the first day of the week; usual for continental Europe.</li>
<li><code>-E</code> further Europeanizes the calendar, setting date convention to, well, European <code>day/month</code> (instead of the American <code>month/day</code>).</li>
</ul>
<p>Run as is, the command above produces calendar of the current month. To produce calendars for a specified month, add <em><code>month year</code></em> to the <code>pcal</code> command line (for example, <code>07 2013</code> for July of 2013).</p>
<p>You will need the second command only if you will copy the resulting calendar to systems, which may not have a Postscript-compatible printer. This command converts the calendar from Postscript into the Portable Document Format, more widely known by it's abbreviation, PDF. The program <code>ps2pdf</code> is a part of ghostscript package, which processes Postscript files.</p>
<p>Of course <code>pcal</code> does have many more options, but if you are content with the calendar at the beginning of this article, just use the commands above.</p>BF interpreters in XSLT and in Scratchhttps://ofdigitalwater.postach.io/post/bf-interpreters-in-xslt-and-in-scratch2018-09-11T16:43:15.068000Z2011-12-26T12:47:59ZWincent Balin<p>This release features Brainfuck interpreter in XSLT. It is in <a href="https://github.com/wincentbalin/BFXSLT">this repository</a>.</p>
<p>Most information is in the file <code>Readme.txt</code>. From there on, you will know how to use the interpreter.</p>
<p>Another feature in this release is the Brainfuck interpreter in Scratch, which can be found <a href="http://scratch.mit.edu/projects/wincent/740588" title="Brainfuck interpreter in Scratch">here</a>. Feel free to remix it.</p>Web server on a 8051 microcontrollerhttps://ofdigitalwater.postach.io/post/web-server-on-a-8051-microcontroller2019-06-15T11:27:36.605000Z2011-12-25T23:43:35ZWincent Balin<p>A couple of years ago it was rather fashionable to create a web server in a microcontroller, most often in a <a href="http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010229">Microchip PIC 16F84 microcontroller</a>. The latter has been chosen because of easy programmability, I surmise. But each implementation had at least one thing about it I disliked: <a href="http://www.sics.se/~adam/miniweb/" title="Miniweb minimal web server">one</a> used a preprocessor to translate web page contents to TCP/IP packet payloads, which required one additional step before compiling, <a href="http://web.archive.org/web/20021003111042/http://www.rmbeales.fsnet.co.uk/files/html/picserver/picservd.htm" title="PIC Web server implementation">another one</a> used an external EEPROM for storage of the said contents; a <a href="http://www.kyllikki.org/hardware/wwwpic2/" title="WWWPic2 minimal web server implementation">third one</a> did not have an external EEPROM, but had much less than 1 kb for web page data storage. Besides, almost all of them had been written in assembler. These implementations impressed me, but they did not have enough appeal for being rebuilt.</p>
<p>All of a sudden, seeing <a href="http://www.atmel.com/products/microcontrollers/8051architecture/default.aspx" title="8051 clones from Atmel">easily programmable 8051 clones from Atmel</a>, which had between 16 and 64 kb flash memory and (as all 8051-based microcontrollers have) a hardware UART, I decided to implement a minimal web server by myself, choosing C as the appropriate programming language. This can be seen as an experiment in compatiblity, both in hardware, because the resulting web server runs on any 8051 clone with enough program memory and in software, because it might be ported to any architecture, for which a C compiler exists. The first of the mentioned implementations, <a href="http://dunkels.com/adam/miniweb/" title="Miniweb minimal web server">Miniweb</a>, appeared to be a good starting point before the discovery that fixed TCP/IP packets made it somewhat inflexible. Another implementation, <a href="http://dunkels.com/adam/phpstack/" title="Web server implementation in PHP">phpstack</a>, by the same author, came as the main inspiration instead. The results are packed into <a href="https://github.com/wincentbalin/httppong">this repository</a>.</p>
<p>Much information about the development, as well as the BSD license, under which this web server implementation is published, reside in the file <code>Readme.txt</code>. Working with the 8051 architecture meant to stick with <a href="http://sdcc.sf.net" title="Small Devices C Compiler">SDCC</a>. The development was conducted under Windows; instead of using a building utility such as <code>make</code>, two DOS batch files were used, <code>c.bat</code> for compilation and conversion of the resulting file to the programmable Intel HEX format and <code>c-clean.bat</code> for cleaning the directory.</p>
<p>The server communicates over a <a href="https://en.wikipedia.org/wiki/SLIP">SLIP</a> connexion (therefore you will need a serial port), using the address <code>192.168.3.2</code>, communicating with 2400 bps at clock frequency of 12 MHz, or 4800 bps at 24 MHz. Internally, the server uses the standard 8051 UART and Timer1 to generate correct timings for the UART. The most basic, characters only, connexion, resides in the file <code>pingpong.c</code>. It answers the input <em>ping</em> with <em>pong</em> (it just translates an <em>i</em> to <em>o</em>, echoing all other characters back), hence the naming of all source files, as all implementations are expected to answer reactively to the input.</p>
<p>Next higher implementation, SLIP only, is implemented in the file <code>slippong.c</code>. An implementation using IP is in the file <code>ippong.c</code>. It also implements ICMP, so from this implementation on, you may ping the server and receive answers. TCP is added in the file <code>tcppong.c</code>. The final implementation is in the file <code>httppong.c</code>. The file <code>httppong.hex</code> contains ready-to-flash firmware, working at the aforementioned IP address with the aforementioned parameters. The implementation uses 76 bytes of RAM and (with current HTML data) 2950 bytes of ROM. To reduce usage of RAM, banking techniques of the 8051 were employed.</p>
<p>Useful data is in the array <code>welcomepage</code>, which was placed in ROM. Update this array with new data. Recompile. Flash. Use.</p>Korg Monotron settings sheethttps://ofdigitalwater.postach.io/post/korg-monotron-settings-sheet2018-09-11T16:43:13.266000Z2011-12-22T14:31:56ZWincent Balin<p><a href="http://www.korg.com/monotrons" title="Korg Monotron series">Korg Monotron</a> is a small and, for its size, a very versatile synthesizer. If there would ever be a competition for the title <em>My first synthesizer ever</em>, Monotron would surely would have been placed first, as all controls are presented to the musician <em>enface</em>, without any menu diving at all. Currently, two newer models are also available, but the theme of this post is the original Monotron only.</p>
<p>An ability, which, in my opinion, Monotron lacks, is the storage of multiple settings. An on-paper storage would mitigate that, I thought. Searching on the Internet pointed to the <a href="http://www.tuerkmusic.co.za/index.php/blog/article/monotron-recall-sheet">Monotron recall sheet</a>, but for my taste, it was too graphic, almost a reproduction of the real Monotron front panel; knobs were too small and the dirty-paper background was not helpful either.</p>
<p>Hence, I redrew the front panel more schematically. Wider knobs allow to see the angle, at which a knob is set, better. The overall picture is smaller, which allows to get ten settings onto a DIN A4 sheet instead of six. The overall ascetic quality of the settings sheet helps to avert distraction of the user. The published materials consist of three parts:</p>
<ul>
<li><a href="https://wincent.balin.at/files/monotron1.svg">Monotron front panel (SVG)</a></li>
<li><a href="https://wincent.balin.at/files/monotron.svg">Monotron settings sheet source (SVG)</a></li>
<li><a href="https://wincent.balin.at/files/monotron.pdf">Monotron settings sheet source (PDF)</a></li>
</ul>
<p>Below you can see the demo (the first file):</p>
<p><img alt="Monotron front panel (SVG)" src="https://wincent.balin.at/files/monotron1.svg" /></p>
<p>The PDF file might be scaled to other paper formats; the crucial condition is the ability of the reader to recognize previously noted settings. The sheet was created using <a href="http://www.inkscape.org">Inkscape</a>.</p>
<hr />
<p><a href="
http://creativecommons.org/licenses/by/3.0/
" rel="license"><img style="border-width: 0;" src="
http://i.creativecommons.org/l/by/3.0/88x31.png
" alt="Creative Commons License" /></a><br />
Korg Monotron settings sheet by <a href="
http://wincent.balin.at/
" rel="cc:attributionURL">Wincent Balin</a> is licensed under a <a href="
http://creativecommons.org/licenses/by/3.0/
" rel="license">Creative Commons Attribution 3.0 Unported License</a>.<br />
Based on a work at <a href="
http://www.tuerkmusic.co.za/index.php/blog/article/monotron-recall-sheet
" rel="dct:source"><br />
www.tuerkmusic.co.za<br />
</a>.</p>PDQt 0.9 releasedhttps://ofdigitalwater.postach.io/post/pdqt-0-9-released2018-09-11T16:43:19.549000Z2011-12-21T00:22:44ZWincent Balin<p><a href="https://github.com/wincentbalin/PDQt/">PDQt</a> is at version 0.9 now.</p>
<p>The <a href="https://github.com/wincentbalin/PDQt/issues/2">GUI issue</a> was solved. The problem lay in too many screen updates.</p>
<p>Aside from this issue, which concerned Qtopia binaries only, the code has been cleaned up only, without changes to the rest. The Win32 binary remained unchanged.</p>Migration from katastrophos.net completehttps://ofdigitalwater.postach.io/post/migration-from-katastrophos-net-complete2018-09-11T16:43:16.372000Z2011-12-15T01:54:00ZWincent Balin<p>Dear readers,</p>
<p>the migration of this blog from its old address is complete. Please update your bookmarks.</p>Problem and solution for ez430 RF2500 port of Contiki OShttps://ofdigitalwater.postach.io/post/problem-and-solution-for-ez430-rf2500-port-of-contiki-os2018-09-11T16:43:11.169000Z2011-04-08T14:08:56ZWincent Balin<p>The archive on the <a href="contiki-port-for-ez430-rf2500-board">page of this port</a> has too many files removed. You will get errors about missing files trying to compile the example.</p>
<p>Just unpack the archive over the plain source of Contiki OS 2.3 and then everything should work fine.</p>BeepTimer for STM32 Primer releasedhttps://ofdigitalwater.postach.io/post/beeptimer-for-stm32-primer-released2018-09-11T16:43:21.570000Z2010-07-26T11:41:36ZWincent Balin<p><a href="http://www.stm32circle.com/projects/project.php?id=122" title="BeepTimer project page">BeepTimer</a> is a successful experiment in Human-Computer Interaction. The question to test was the possibility to control a device using one acceleration sensor and one button. As already mentioned, it is possible even with OS functions intervening (long button press issues a shutdown of the device). The user controls the device by tilting it and by pushing the button. The description of possible gestures is provided on the <a href="http://www.stm32circle.com/projects/project.php?id=122" title="BeepTimer project page">project page</a>.</p>GraspForth on STM32 Primer releasedhttps://ofdigitalwater.postach.io/post/graspforth-on-stm32-primer-released2018-09-11T16:43:09.759000Z2010-07-19T14:23:35ZWincent Balin<p><a href="http://forthfreak.net/index.cgi?GraspForth" title="GraspForth ForthFreak Wiki page">GraspForth</a> is a simple, portable implementation of a Forth system in C. It works every 32-bit architecture GCC compiles for. The <a href="http://www.stm32circle.com/" title="STM32 Primer platforms">STM32 Primer</a> devices were introduced on this blog <a href="contiki-on-circleos">earlier</a>. These systems were combined in the <a href="http://www.stm32circle.com/projects/project.php?id=121" title="GraspForth on STM32 Primer">GraspForth on STM32 Primer</a> project. If you are interested, read <a href="http://www.stm32circle.com/projects/project.php?id=121" title="GraspForth on STM32 Primer">the rest of the project's description</a>.</p>PDQt 0.8 releasedhttps://ofdigitalwater.postach.io/post/pdqt-0-8-released2018-09-11T16:43:19.562000Z2010-07-10T23:35:25ZWincent Balin<p><a href="http://github.com/wincentbalin/PDQt/">PDQt</a> is at version 0.8 now.</p>
<p>The function of the Action button was divided between the Shift button (Shift key) and the Action button (Return key).</p>
<p>Furthermore, now PDQt recognizes circling gestures. Circling around the center of the program's screen clockwise increases the current value, circling counter-clockwise decreases it.</p>
<p>You may download the new package for Cacko and maybe other Qtopia based distributions from <a href="http://github.com/wincentbalin/PDQt/releases/tag/V0.8">this page</a>. Otherwise you might want to <a href="http://github.com/wincentbalin/PDQt/">download the source code</a> and compile it for yourself — you will need Qt3 compilation environment only, either on Win32 or on Linux.</p>PDQt 0.75 releasedhttps://ofdigitalwater.postach.io/post/pdqt-0-75-released2018-09-11T16:43:18.564000Z2010-07-08T23:47:01ZWincent Balin<p><a href="http://github.com/wincentbalin/PDQt/">PDQt</a> is at version 0.75 now.</p>
<p>The key map was adapted for a usual computer keyboard; <code>Space</code> is the <code>Play</code> button now instead of <code>C</code>, <code>Shift</code> is the <code>Action</code> button instead of <code>D</code> et cetera. Furthermore, mouse wheel can be used now for changing values. Look into the help dialog for explanations.</p>
<p>You may download the new package for Cacko and maybe other Qtopia based distributions from <a href="http://github.com/wincentbalin/PDQt/releases/tag/V0.75">this page</a>. Otherwise you might want to <a href="http://github.com/wincentbalin/PDQt/">download the source code</a> and compile it for yourself — you will need Qt3 compilation environment only, either on Win32 or on Linux.</p>PDQt 0.7 releasedhttps://ofdigitalwater.postach.io/post/pdqt-0-7-released2018-09-11T16:43:18.665000Z2010-07-03T23:54:54ZWincent Balin<p><a href="http://github.com/wincentbalin/PDQt/">PDQt</a> is at version 0.7 now. There are no visible additions or corrections on the user side. All changes were internal. You may download the new package for Cacko and maybe other Qtopia based distributions from <a href="http://github.com/wincentbalin/PDQt/releases/tag/V0.7">this page</a>. Otherwise you might want to <a href="http://github.com/wincentbalin/PDQt/">download the source code</a> and compile it for yourself — you will need Qt3 compilation environment only, either on Win32 or on Linux.</p>