Hi there! My name is Adrian Kummerländer and I am a software developer currently studying mathematics in Karlsruhe. On these pages you will find blog articles covering amongst other topics some of my experiences in software development, open source and self hosting as well as repositories and information on some of my personal projects. If you have any comments or questions feel free to reach out. I hope you will find something here worth your time.
If the contents of this website are of interest to you chances are that you also know how easy it is to spend large parts of one's leisure time tinkering with computer systems and improving workflows while losing sight of what one actually wants to accomplish. I am going to use this article to document parts of my current personal computing setup in an attempt to summarize and refocus my efforts in this direction in addition to articulating some of my thoughts in this context. ↪May 22, 2016 | Adrian Kummerländer
In der Analysis 2 Vorlesung meines Mathematik Studiums beschäftigen wir uns derzeit mit Normen und Metriken in endlich dimensionalen Vektorräumen, welche wiederum die Grundlage für die Übertragung der, aus Analysis 1 bekannten, Konvergenz und Stetigkeitsbegriffe in höhere Dimensionen schaffen. Während der Bearbeitung der entsprechenden Übungsblätter habe ich dabei nach Visualisierungsmöglichkeiten recherchiert, um eine bessere Intuition für diese Begriffe zu erlangen. Voronoi-Diagramme sind eine solche Möglichkeit, deren Grundlagen und Generierung ich in diesem Artikel zwischen Theorie und Praxis näher erläutern möchte. ↪February 21, 2016 | Adrian Kummerländer
To counterbalance the vastly increased amount of time I am spending on purely theoretical topics since I started studying mathematics, my most recent leisure time project was to familiarize myself with function interposition in C++ on Linux. This article will document some of the ins and outs of using this technique in an actual project in addition to describing how the acquisition of the interposed function's pointer may be reasonably abstracted by a function template. ↪April 13, 2017 at 19:51 | slang | d2126f | Adrian Kummerlaender
Due to the non-trivial way tokens were previously processed the compiler could not safely perform tail-call elimination. Thus the slang evaluation depth was restricted by the maximum call stack size.
This issue is mitigated by introducing deferred word resolution - i.e. pushing expanded tokens onto a buffer stack and processing them in an explicit loop.
This change ties into the implementation of the language's conditional primitive. The previous implementation did implicitly not support direct nesting of conditional expressions such as:
truthA if mainBranch truthB if secondaryMainBranch then else then alternativeBranch else
This issue is now made explicit by disallowing direct nesting of conditionals as depicted above. Appropriate exceptions are generated when required and the conditional primitive is reimplemented in a more robust fashion under the assumption that this rule holds. Note that nesting is still fully supported iff. the nested conditional is contained in a deferredly evaluated word. As a positive side effect this will make it slightly harder to generate unreadable code by forcing developers to write simpler words.
The main change of the conditional primitive lies in deferring branch token processing until the conditional expression is concluded by
else. This is achieved by capturing non-dropped tokens in an internal buffer akin to how the word definition operator
§ is implemented. The branch buffer is discharged after
else is evaluated. Discharging is triggered via the newly introduced
result method of the primitive evaluation module. This avenue for injecting tokens into the processing stream may be used by further primitives in the future.
1 if true then false else evaluates to
0 if true then false else evaluates to
The trigger but not the actual reason for this replacement of
pandoc was a strange generation issue with
kramdown's latest release.
All recent articles failed to generate anything more than an empty page. A quick check of the resulting HTML for those articles offered nothing out of the ordinary. After taking a close look at the articles in question I narrowed the set of failing articles down to those containing footnotes - tangentially I only started using footnotes a couple of articles ago i.e. this explained this part of the issue.
Some debugging of
InputXSLT offered the following problem:
Xerces-C generated an error message and stopped processing XML inputs containing
nbsp non-blocking space characters in the implementation of the
external-command function. This change in
kramdown's output can be traced back to enhancement issue 399. Obviously this is not a problem in
kramdown but an issue in the way this static site generator is wrapping HTML inputs.
This problem should be solvable by adding appropriate namespace and doctype declarations to the markdown-generated HTML output. Instead I opted to perform the change to
pandoc I had already planned for quite some time.
The choice fell on
pandoc as it offers some additional markdown features as well as allowing for conversion to a rich set of document formats. i.e. features like printing articles as PDF using LaTeX are trivial to implement if
pandoc is the markdown processor of choice. Furthermore page compilation is noticeably faster using
One might note that this switch only solved the original issue by coincidence: Should
pandoc start to generate non-blocking space characters the same problem will occur. But I have hopes that such a change would be configurable via
pandoc's plethora of configuration options. As this static site generator assumes everything to be XHTML I see no reason why I should not continue to treat HTML inputs as XML.
Many websites employ the MathJax library for dynamically rendering LaTeX math expressions on the client side. I expect to require support for doing just that in the future. But as with syntax highlighting I am of the opinion that this kind of stuff should be performed once during site compilation instead of wasting ressources by forcing each client to do this job for every single page request.
Luckily there is a MathJax-node module that allows using the MathJax library on the server side.
This commit adds support for rendering math expressions written in Markdown respectively LaTeX as follows:
$$1 + 1 \neq 0$$ on the server side.
This required the introduction of a new
math_highlighter helper template in
formatter.xsl based on the
tex2html utility provided by MathJax-node. This formatter is matched against the (Markdown parser generated)
script node in
formatter.xsl's embellish mode. The HTML rendering of the expression is then embedded in a
p class="math" node. This explicit labeling allows
master.xsl to include the
math.css rules only for pages that actually contain math expressions.
Note that the XHTML rendering utility stylesheet
xhtml.xsl currently adds a XML comment to each
span node. This is a workaround to prevent Xalan from collapsing "empty"
span tag pairs into single nodes which otherwise leads to rendering errors as it is not valid HTML and is interpreted as a wrong tree structure by the browser.
Note that the CSS rules declared in
math.css are explicitly not part of the MIT licensed part of this repository but where generated by MathJax.
As there is currently no productive content making use of math expressions a demo page is available under
open is not as side effect free as I had imagined - i.e. if the flag
O_TRUNC is passed it truncates the file contents alongside opening the file descriptor. In practice this is done by emacs prior to writing the new file content and as such needs to be intercepted so we can start tracking the file before it is changed.
open required some changes to make the library work without including
fcntl.h. This header not only defines some of the flags we require to check if a library call actually is able to change files but also defines the
open library function.
While implementing this change I noticed that the function interpositions implemented in C++ actually need to be declared as
external "C" so their names do not get wrangled during compilation. I suspect that this was previously implicitly done for e.g.
write by the included C standard library headers. However this did not work for
open which is why all function interpositions are now explicitly declared external.
End result: emacs file changes are now tracked correctly.February 17, 2016 at 14:02 | change | af756d | Adrian Kummerlaender
The previous interposition logic based on plain usage of
dlsym analogously to various online examples led to a deadlock during neovim startup. This deadlock was caused by neovim's custom memory allocation library jemalloc because it calls
mmap during its initialization phase. The problem with calling
mmap during initialization is that this already leads to executing
mmap version whoes static
actual_mmap function pointer is not initialized at this point in time. This is detected and leads to a call to
dlsym to remedy this situation. Sadly
dlsym in turn requires memory allocation using
calloc which leads us back to initializing jemalloc and as such to a deadlock.
I first saw this as a bug in jemalloc which seemed to be confirmed by a short search in my search engine of choice. This prompted me to create an appropriate bug report which was dismissed as a problem in the way
mmap was interposed and not as a bug in the library. Thus it seems to be accepted practice that it is not the responsibility of a custom memory allocator to cater to the initialization needs of other libraries relying on function interposition. This is of course a valid position as the whole issue is a kind of chicken and egg problem where both sides can be argued.
To cut to the chase I was left with the only option of working around this deadlock by adapting
libChangeLog to call
dlsym without relying on the wrapped application's memory allocator of choice. The most straight forward way to do this is to provide another custom memory allocator alongside the payload function interpositions of
mmap and friends.
init/alloc.cc implements such a selectively transparent memory allocator that offers a small static buffer for usage in the context of executing
dlsym.The choice between forwarding memory allocation requests to the wrapped application's allocator and using the static buffer is governed by
init::dlsymContext. This tiny helper class maintains an
dlsym_level counter by posing as a scope guard.
The end result of this extension to
libChangeLog is that it now also works with applications using jemalloc such as neovim and should overall be much more robust during its initialization phase.
The library may be provided with a new-line separated list of regular expressions via the newly introduced
Any proposed tracking path that is matched by any of the provided patterns is excluded from change reporting. This functionality uses the Standard's regular expression parsing functionality and as such doesn't introduce any new dependencies. If no file path is provided or the provided file path is unreadable all paths will be tracked.
change was adapted to set
.change_log_ignore which means that it will by default exclude any patterns provided via this file in the current working directory.
An example for such a file customized for hiding vim's internal write logic may look as follows:
[0-9]+ [^~]*~ [.*\.viminfo .*\.swp
Note that this is implemented in a fashion where it is not guaranteed that the full canonical path is checked against the patterns. It remains to be decided if this is enough for all common use cases of this new functionality.
February 11, 2016 at 17:43 | change | 7582ab | Adrian Kummerlaender
tracking::PathMatcher lacks any explicit thread synchronization - according to my current knowledge this should not be necessary as we are only ever reading the private
std::vector<std::regex> instance. If invalid regular expressions are provided they are silently ignored.
Introduce global static
enabled variable used to signal the interposed functions to either start tracking or perform plain forwarding without any additional logic. This is required as e.g.
nvim crashed when wrapped in
libChangeLog because it called interposed functions during library initialization.
In addition to increasing customizability this change makes it clear that the working directory property only concerns the intial working directory and is not updated if the contained process changes its directory.
Note that setting the intial working directory is broken in upstream QMLTermWidget and the appropriate patch 1 is not merged at the time of this commit.September 4, 2015 at 20:05 | MetaTerm | 52dd09 | Adrian Kummerlaender
kill merely destroyed the terminal widget. This is contrary to the expected notion of
kill, i.e. actually killing the process explicitly instead of relying on side effects.
The normal mode
d verb now explicitly destroys the current item's content, be it a terminal widget or a history view.
August 29, 2015 at 20:12 | MetaTerm | 0dd495 | Adrian Kummerlaender
reset member method wrongly performed a visual selection change which led to inconsistency when calling
kill on a non-selected index. Visual selection update is now performed on history view instantiation.
Child processes of MetaTerm may be terminated using other ways that the integrated kill command. Automatic terminal widget destruction in such a event prevents the user from viewing the output of non-interactive applications. This requires MetaTerm to display the application's output after it was terminated. This requirement is implemented via the new
HistoryViewer widget that is instantiated after the terminal widget instance has been destroyed.
This enables the user to straight forwardly change all application settings via command mode.
During the implementation of this change I discovered that the way I was passing around
SettingsHandler instances using properties was unnecessary. If all object instances are created in a common hierarchy they can access each other by their
id property - i.e.
mode are available to the whole application without property trickery.
June 10, 2015 at 18:32 | SimpleParser | 0985a6 | Adrian Kummerlaender
list holds the components of the central list UI element.
command holds the UI and implementation parts of the command mode.
widget holds more or less general purpose elements that may also be of use in other circumstances.
- all non operator and digit tokens are now identifier tokens as this seems more intuitive than generating number token lists containing non-digit values
- renamed lexer-local
nestingas to avoid confusion between nesting state and predecence levels
machine::simulatenow returns a list of all tape states and corresponding head positions
- rewrote some of the actual print logic in terms TypeAsValue