<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Webrunners</title>
	<atom:link href="https://www.webrunners.de/en/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.webrunners.de</link>
	<description>Softwareentwicklung und Webentwicklung aus Köln</description>
	<lastBuildDate>Sat, 13 Sep 2025 12:22:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.webrunners.de/wp-content/uploads/2019/10/cropped-Favicon_Zeichenfläche-1-32x32.png</url>
	<title>Webrunners</title>
	<link>https://www.webrunners.de</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Our Hackathon from the ChatGPT</title>
		<link>https://www.webrunners.de/en/15119-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=15119-2</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Mon, 23 Jan 2023 11:53:33 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">https://www.webrunners.de/?p=15119</guid>

					<description><![CDATA[<p>Our team meets at regular intervals to work on projects together, to programme or to hold a &#8220;hackathon&#8221;. It is important to us that every team member can be involved, so that even non-developers can try things out and contribute to the final result. At our last hackathon, we developed a remote-controlled camera vehicle that [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/15119-2/">Our Hackathon from the ChatGPT</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>Our team meets at regular intervals to work on projects together, to programme or to hold a &#8220;hackathon&#8221;. It is important to us that every team member can be involved, so that even non-developers can try things out and contribute to the final result.</p>



<p>At our last hackathon, we developed a remote-controlled camera vehicle that can be controlled from anywhere in the world via an internet connection. But before we now write ourselves how we did it, we wrote the following article as an experiment with ChatGPT.</p>



<p>ChatGPT is a prototype of a chatbot that uses artificial intelligence and is constantly being trained by the feedback of users. Thus, ChatGPT can conjure up complete solutions and texts on the screen within a few seconds using a few keywords. Afterwards, we asked ourselves which articles, codes and texts we had read last were actually written by humans.</p>



<p>But feel free to read the following text for yourself. We have translated the content below into German ourselves, you can find the original version in the English version.</p>



<p>We have provided ChatGPT with the following key points:<br>Write a longer blog article about a hackathon that the Webrunners team hosted in the company&#8217;s CreativeSpace. There we built a remote zoom camera vehicle and programmed an application to control it. This allows remote workers to remotely control the camera van and the position of the camera itself.<br>While the on-site staff assembled the hardware, set up the RaspberryPi and made it accessible to the outside via a tunnel, the remote staff built the application. In order to involve the remote workers as much as possible in the on-site collaboration, we set up several cameras, including a 360° camera that allowed for good integration. The result of the day was a first proof of concept, where the vehicle base and the camera could be controlled remotely. Now the individual aspects can be optimised and components, such as a robotic arm for finer control of the camera, can be developed with the 3D printer.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">We have provided ChatGPT with the following key points</h3>



<p>Write a longer blog article about a hackathon that the Webrunners team held in the company&#8217;s creative space. There we built a remote zoom camera vehicle and programmed an application to control it. Remote workers can use it to remotely control the camera vehicle and the position of the camera itself.<br>While the on-site employees assembled the hardware, set up the RaspberryPi and made it available to the outside via a tunnel, the remote employees built the application. To ensure that the remote workers were as involved as possible in the on-site collaboration, we set up several cameras, including a 360° camera that enabled good integration. The day&#8217;s result was an initial proof of concept, with the vehicle base and camera remotely controllable. Now the individual aspects can be optimized and components, such as a robotic arm for finer control of the camera can be developed with the 3D printer.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">ChatGPT result</h3>



<p>Last week, the Webrunners team held a hackathon at the company&#8217;s creative space. The goal was to come up with innovative solutions to common problems faced by remote workers, and we were excited to see what we could accomplish.<br>One of the ideas that we came up with was to build a remote zoom camera vehicle that could be controlled by a remote worker. This would allow remote workers to have more control over their camera position during team meetings, and would also allow them to move the camera around the room if needed.<br>To get started, we split the team into two groups. One group consisted of on-site employees who were responsible for assembling the hardware and setting up the RaspberryPi. They also made the vehicle available to the outside via a tunnel, so that the remote workers could access it.<br>The other group consisted of remote workers who were responsible for building the application that would control the vehicle. To ensure that the remote workers were as involved as possible in the on-site collaboration, we set up several cameras, including a 360° camera that enabled good integration.<br>Over the course of the hackathon, the two teams worked together to build and program the remote zoom camera vehicle. By the end of the day, we had a functional proof of concept, with the vehicle base and camera both being remotely controllable.<br>While we were pleased with the progress we made during the hackathon, we also realized that there was still more work to be done. There were several aspects that we needed to optimize, and we also wanted to develop components such as a robotic arm for finer control of the camera. We decided to use the 3D printer to create these components, which would allow us to customize the vehicle to meet our specific needs.<br>Overall, the hackathon was a great success for the Webrunners team. We were able to come up with a creative and innovative solution to a common problem faced by remote workers, and we had a lot of fun doing it. We&#8217;re excited to continue working on the remote zoom camera vehicle and see how it can help to improve the experience of remote meetings.</p>



<figure class="wp-block-gallery has-nested-images columns-2 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-17.jpeg"><img fetchpriority="high" decoding="async" width="640" height="435" data-id="15111" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-17.jpeg" alt="" class="wp-image-15111" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-17.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-17-300x204.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-24.jpeg"><img decoding="async" width="480" height="640" data-id="15110" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-24.jpeg" alt="" class="wp-image-15110" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-24.jpeg 480w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-24-225x300.jpeg 225w" sizes="(max-width: 480px) 100vw, 480px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-15.jpeg"><img decoding="async" width="640" height="384" data-id="15109" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-15.jpeg" alt="" class="wp-image-15109" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-15.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-15-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-8.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15107" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-8.jpeg" alt="" class="wp-image-15107" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-8.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-8-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-5.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15106" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-5.jpeg" alt="" class="wp-image-15106" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-5.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-5-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-4.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15103" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-4.jpeg" alt="" class="wp-image-15103" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-4.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-4-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-7.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15102" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-7.jpeg" alt="" class="wp-image-15102" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-7.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-7-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-18.jpeg"><img loading="lazy" decoding="async" width="640" height="433" data-id="15101" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-18.jpeg" alt="" class="wp-image-15101" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-18.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-18-300x203.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-10.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15100" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-10.jpeg" alt="" class="wp-image-15100" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-10.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-10-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-12.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15099" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-12.jpeg" alt="" class="wp-image-15099" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-12.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-12-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-20.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15105" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-20.jpeg" alt="" class="wp-image-15105" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-20.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-20-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-3.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15098" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-3.jpeg" alt="" class="wp-image-15098" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-3.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-3-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-23.jpeg"><img loading="lazy" decoding="async" width="640" height="480" data-id="15104" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-23.jpeg" alt="" class="wp-image-15104" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-23.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-23-300x225.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-19.jpeg"><img loading="lazy" decoding="async" width="640" height="453" data-id="15108" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-19.jpeg" alt="" class="wp-image-15108" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-19.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-19-300x212.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-16-1.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15097" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-16-1.jpeg" alt="" class="wp-image-15097" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-16-1.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-16-1-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-1.jpeg"><img loading="lazy" decoding="async" width="640" height="384" data-id="15096" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-1.jpeg" alt="" class="wp-image-15096" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-1.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-1-300x180.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-25.jpeg"><img loading="lazy" decoding="async" width="640" height="480" data-id="15112" src="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-25.jpeg" alt="" class="wp-image-15112" srcset="https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-25.jpeg 640w, https://www.webrunners.de/wp-content/uploads/2023/01/2022-12-Hackthon-Zoom-Car-25-300x225.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></figure>
</figure>The post <a href="https://www.webrunners.de/en/15119-2/">Our Hackathon from the ChatGPT</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Dockermen&#8217;s introduction to private docker hub with GitLab</title>
		<link>https://www.webrunners.de/en/dockmen-on-gitlab/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dockmen-on-gitlab</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Wed, 08 Jun 2016 15:21:37 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=539</guid>

					<description><![CDATA[<p>1 Since end of May, thanks to the great efforts of the GitLab project developers, an open source authorization-layer for the docker-registry(v2) is available. Within this article I´d like to introduce my collegues into the basic steps to work with docker and our new private docker-registry. The so called docker-registry is like a git-repository for [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/dockmen-on-gitlab/">Dockermen’s introduction to private docker hub with GitLab</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<hr />
<p><sup id="fnref-1"><a href="#fn-1" rel="footnote">1</a></sup></p>
<p>Since end of May, thanks to the great efforts of the GitLab project developers, an open source authorization-layer for the <a href="https://github.com/docker/distribution">docker-registry(v2)</a> is <a href="https://about.gitlab.com/2016/05/23/gitlab-container-registry/">available</a>.<br />
Within this article I´d like to introduce my collegues into the basic steps to work with docker and our new private docker-registry.</p>
<p><span id="more-539"></span></p>
<p>The so called docker-<em>registry</em> is like a git-repository for so called docker-<em>images</em>.</p>
<h3>Enable the registry for your project</h3>
<ol>
<li>Sign in to <a href="https://code.webrunners.de">code.webrunners.de</a></li>
<li>Go to your project: <em>/namespace/projectname</em></li>
<li>Click on Settings: <em>/namespace/projectname/edit</em></li>
<li>Under &#8220;<em>Features</em>&#8221; enable &#8220;<em>Container registry</em>&#8221; and save</li>
<li>Go back to project and click on the new available &#8220;<em>Container Registry</em>&#8220;</li>
</ol>
<p>This is the page where you will see and manage your pushed images.<br />
There is also a nice little help written.</p>
<p>Now your project-namespace is ready to use for pushing and pulling docker images.</p>
<h3>Example of usage</h3>
<p>On your command line:</p>
<ol>
<li>Create a docker image</li>
<li>Name (tag) it to <em>registry.webrunners.de/namespace/projectname:tag</em></li>
<li>Login docker to our registry</li>
<li>Push the image</li>
<li>Now, others with project-access are able to pull it</li>
</ol>
<p>Assuming you already have installed docker for your OS&#8230;:</p>
<ul>
<li><a href="https://docs.docker.com/engine/installation/windows/">Windows</a></li>
<li><a href="https://docs.docker.com/engine/installation/mac/">Mac OS X</a></li>
<li><a href="https://docs.docker.com/engine/installation/linux/ubuntulinux/">Ubuntu</a></li>
<li><a href="https://docs.docker.com/engine/installation/">Other</a></li>
</ul>
<p>&#8230;you should be able to execute the docker client on your command line.</p>
<h3>Let´s start</h3>
<p>Docker, as it is one big binary that is written in <a href="https://golang.org/">Golang</a>, has different subcommands.</p>
<p>I will list some in a meaningful order:</p>
<pre><code>docker ps # List all currently running processes (docker container)
docker images # List all images, which are the base for containers
docker run image/name # Start a container from an image
</code></pre>
<p>Containers are like linked clones to images. You can think of containers as running state and images as frozen state. They don´t alter the images, but are a new isolated layer upon them to make use of preinstalled software.<br />
You can get images from <a href="https://hub.docker.com/">hub.docker.com</a>, or build them locally e.g. to push later to our private registry.</p>
<h3>A simple workflow</h3>
<ol type="I">
<li>Get an public available image from docker hub</li>
<li>Run it locally for testing</li>
<li>Adapt it</li>
<li>Commit it and save it to a new image</li>
<li>Rename the image for pushing to our registry</li>
<li>Deleting locally and rerun/pull to verify all is as expected</li>
</ol>
<p><strong>I)</strong> We get this <a href="https://github.com/elyase/docker/blob/master/staticpython/Dockerfile">very small alternative</a> to the <a href="https://hub.docker.com/r/_/python/">official python image</a>:</p>
<pre><code>docker pull elyase/staticpython
</code></pre>
<p><strong>II)</strong> For Windows you could try <code>%CD%</code> instead of <code>$(pwd)</code>. Alternatively you can write the full path to the current directory. On Windows use this notation: <code>/c/Users/</code></p>
<pre><code>docker run -p 8000:8000 -v $(pwd):/src -w /src --rm -it elyase/staticpython sh -c 'python -m SimpleHTTPServer'
</code></pre>
<h4>Explanation</h4>
<blockquote><p>Don´t forget to check <code>docker --help</code>, <code>docker subcommand --help</code></p></blockquote>
<ul>
<li><code>run</code> &#8211; Subcommand to start an image</li>
<li><code>-p</code> &#8211; Publish a port to the docker-host</li>
<li><code>-v</code> &#8211; Mount a local directory, or a so called <em>Volume</em> within the container</li>
<li><code>-w</code> &#8211; When starting the container use this as the working directory</li>
<li><code>--rm</code> &#8211; After stoping the container, delete it. See <code>docker ps -a</code> for exited containers that might be used again, or just eat disk-space.</li>
<li><code>-it</code> &#8211; Short for <code>-i -t</code>. Start an interactive terminal session</li>
<li><code>elyase/staticpython</code> &#8211; The image to use</li>
<li><code>sh -c 'python -m SimpleHTTPServer'</code> &#8211; All the rest is a command to run. Here we only start a little webserver</li>
</ul>
<p>If you use <a href="https://docs.docker.com/machine/reference/">docker-machine</a>, get the docker-host-IP with <code>docker-machine ls</code>. Now you should be able to open a browser to see your current directory files:</p>
<p>Go to: http://docker-host-IP:8000<br />
For me it´s: http://192.168.99.100:8000</p>
<p>Quit the Container with <code>Ctrl-C</code>.</p>
<p><strong>III)</strong> Now we run the container again in detached mode, and run some commands inside. Note that we don&#8217;t use a shared Volume this time, as it could not be committed to an image. Also we name the container this time.</p>
<pre><code>docker run -d --name charly -p 8000:8000 -w /src -it elyase/staticpython sh -c 'python -m SimpleHTTPServer' # We wrap the python command, because it didn´t respond to Ctrl-C in my tests

docker exec charly sh -c 'echo "We run webs" &gt; index.html' # We have to wrap the command inside the sh command because of the redirection.
</code></pre>
<p>Now I can see the page on 192.168.99.100:8000 again.</p>
<p>We could do some work directly inside a shell session:</p>
<pre><code>docker exec -it charly sh
/src # echo "Go on spider" &gt;&gt; index.html
/src # exit
</code></pre>
<p><strong>IV/V)</strong></p>
<pre><code>docker commit -m "Some test" charly registry.webrunners.de/namespace/project:test
</code></pre>
<p>You should see now the commit under <code>docker images</code>.<br />
And could rename it later with <code>docker tag</code>.</p>
<p>Now use your GitLab credentials:</p>
<pre><code>docker login registry.webrunners.de
</code></pre>
<p>And push</p>
<pre><code>docker push registry.webrunners.de/namespace/project:test
</code></pre>
<p>You can manage the image on:<br />
https://code.webrunners.de/namespace/projectname/container_registry.</p>
<p><strong>VI)</strong> As the container is still running locally and the just created image (commit) still exist, we now delete them.</p>
<pre><code>docker kill charly
docker rm charly
docker rmi registry.webrunners.de/namespace/project:test
docker images
docker ps
</code></pre>
<h4>Verify</h4>
<pre><code>docker run --rm -it registry.webrunners.de/namespace/project:test

Unable to find image 'registry.webrunners.de/namespace/project:test' locally
test: Pulling from namespace/project
...
...
</code></pre>
<h4>Build</h4>
<p>Now we put all of this inside a build script. The so called <em>Dockerfile</em>.</p>
<p>Create two files</p>
<p><strong>index.html</strong></p>
<pre><code>We run webs
Go on spider
</code></pre>
<p><strong>Dockerfile</strong></p>
<pre><code>FROM elyase/staticpython

COPY index.html /src/

WORKDIR /src

CMD ["sh", "-c", "python -m SimpleHTTPServer"]
</code></pre>
<pre><code>docker build -t registry.webrunners.de/namespace/project .
docker tag registry.webrunners.de/namespace/project:latest registry.webrunners.de/namespace/project:spider
</code></pre>
<h4>Check</h4>
<pre><code>docker run -it --rm -p 8000:8000 --name charly registry.webrunners.de/namespace/project:spider
</code></pre>
<p>Open http://192.168.99.100:8000</p>
<h4>Push</h4>
<pre><code>docker push registry.webrunners.de/namespace/project:spider
</code></pre>
<h4>Cleanup</h4>
<h5>Locally</h5>
<pre><code>docker kill charly
docker rm charly
docker rmi registry.webrunners.de/namespace/project:test
docker rmi registry.webrunners.de/namespace/project:spider
docker rmi registry.webrunners.de/namespace/project:latest
docker ps -a
docker images
</code></pre>
<h5>GitLab</h5>
<p>There are buttons to delete the pushed images.</p>
<h3>Bugs</h3>
<p><a href="https://gitlab.com/gitlab-org/gitlab-ce/issues/17875">#17875:</a><br />
Docker push will loop to upload and finally give up on big layers.<br />
This should be fixed in a next GitLab release:</p>
<h3>Reference</h3>
<ul>
<li><a href="https://docs.docker.com/engine/reference/builder/">Dockerfile Reference</a></li>
<li><a href="https://docs.docker.com/engine/reference/run/">Docker run Reference</a></li>
<li><a href="https://docs.docker.com/compose/">Docker compose</a></li>
<li><a href="http://docs.gitlab.com/ce/ci/docker/using_docker_build.html">Gitlab CI using registry</a></li>
<li><a href="https://entwickler.de/online/docker-und-net-ein-beispiel-160431.html">Docker und .NET – ein Beispiel</a></li>
</ul>
<ul>
<li id="fn-1">The Old Sailors’ image by <a href="https://www.flickr.com/photos/brizzlebornandbred/">Paul Townsend </a> is licensed under <a href="https://creativecommons.org/licenses/by-nd/2.0/">CC BY-ND 2.0</a>. <a href="#fnref-1" rev="footnote">↩</a></li>
</ul>The post <a href="https://www.webrunners.de/en/dockmen-on-gitlab/">Dockermen’s introduction to private docker hub with GitLab</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to write cleaner parsing code</title>
		<link>https://www.webrunners.de/en/how-to-write-cleaner-parsing-code/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-write-cleaner-parsing-code</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Thu, 03 Mar 2016 11:43:21 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=448</guid>

					<description><![CDATA[<p>When tasked to extract information from a string, most seasoned developers &#8211; especially the ones with some kind of Linux background &#8211; will resort to regular expressions. While regular expressions are incredibly powerful and very well suited for most parsing jobs, they don&#8217;t scale very well. With increasing complexity they tend to become very cryptic, [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/how-to-write-cleaner-parsing-code/">How to write cleaner parsing code</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>When tasked to extract information from a string, most seasoned developers &#8211; especially the ones with some kind of Linux background &#8211; will resort to regular expressions. While regular expressions are incredibly powerful and very well suited for most parsing jobs, they don&#8217;t scale very well. With increasing complexity they tend to become very cryptic, if not unreadable and therefore eventually unmaintainable.</p>
<p>Another alternative is to use parser combinators that combine small atomic parsers to build a complex rule set.</p>
<p>Let&#8217;s see how we can use parser combinators in an (admittedly simple) context. One of our customers runs a fascinating web service: Using a easy-to-understand URL scheme, you can remotely control a rendering engine that can effectively combine hundreds of different car parts to render a photo-realistic image of a specific car configuration. One task in a recent project was to extract car configuration data from a web service call.</p>
<p><span id="more-448"></span></p>
<h2>A real world example</h2>
<p>Our customer&#8217;s API is confidential, so I had to alter a few specifications and sadly can&#8217;t give any example images.</p>
<p>As mentioned before, the URL scheme is straightforward, but it seems to be more human-friendly than machine-friendly, but more about that later. It consists of the following parts:</p>
<ol>
<li>The country version&#8217;s ISO code</li>
<li>Car metadata (model is mandatory, body and grade are optional)</li>
<li>Optional codes for
<ol>
<li>option codes</li>
<li>equipment packs</li>
<li>accessories</li>
</ol>
</li>
<li>Image metadata like resolution, background colour and car angle</li>
</ol>
<pre><code>https://example.org
    /de
    /vehicle/trabant/5-doors/0815+universal
    /options/1,4711,815
    /packs/p7
    /accessories/a,b,c
    /width/1024
    /height/768
    /exterior-45.jpg
</code></pre>
<p>As you can see, there is a bit of inconsistency that might cause some inconvenience while parsing: the country code doesn&#8217;t have a qualifier, the car model, body and grade info are delimited by slashes, the other fields are delimited by commas. Also there&#8217;s some information encoded in the filename, but we can ignore that as we&#8217;re only parsing the car configuration, not the image metadata.</p>
<h2>The right tool for our task</h2>
<p>The basic idea of any parser combinator is that it takes an input, reads (&#8220;consumes&#8221;) it until it is either <em>done</em> or <em>fails</em>, in both cases returning the <em>result</em> and the <em>remaining unparsed string</em>, which might be fed into subsequent parsers. In this example we will be using the <a href="https://github.com/aslatter/parsec">Parsec library</a> to manage the grunt work for us. It seems well-suited for this task, it&#8217;s quite readable and as straightforward as something that calls itself &#8220;industrial strength, monadic parser combinator&#8221; can be and there are many clones and implementations in various programming languages.</p>
<p>Parsec is written in the pure functional programming language Haskell, but to understand the examples in this post, you won&#8217;t need to understand Haskell. I chose Haskell for the code examples because the parsers contain barely any language-specific syntax, all the handling is nicely kept away from us, making the code almost look like pseudo code.</p>
<h2>Writing the parser</h2>
<p>As mentioned earlier, a parser combinator is built up from simple building blocks combined to complex parsers. There are quite a lot predefined parsers for common tasks that we can re-use and combine. It&#8217;s fascinating that all parsers are independent and can be executed on their own, so everything is easily maintainable and testable.</p>
<h3>Parsing characters and letters</h3>
<p>We&#8217;re dealing with a URL, so even without knowing the specs, we can guess that we will encounter &#8220;things delimited by slashes&#8221;. According to the web service specification, these &#8220;things&#8221; can only consist of characters and numbers. We&#8217;ll start with a parser that reads these symbols between the slashes and call it <code>value</code>.</p>
<aside>Functions in Haskell are defined by just assigning a value to a name. Haskell doesn&#8217;t need parentheses around and commas between function parameters.</p>
<p>The parsers after the <code>do</code> are executed in sequential order, automatically feeding the unparsed result of one parser into the next one. If only one parser is called, <code>do</code> can be omitted.</p>
<p>Explaining what exactly is going on under the hood would go beyond the scope of this article, but there are some excellent Haskell resources linked in the last section.</p>
</aside>
<pre><code class="language-haskell">value = do
    many1 alphaNum
</code></pre>
<p><code>many1</code> and <code>alphaNum</code> are parsers already defined in the Parsec library. When run, our combined parser expects one or more (<code>many1</code>) alphanumeric symbols, i.e. letters or numbers (<code>alphaNum</code>). If the input matches these characters it will succeed, if it encounters any other symbol, it will fail. The result of the last line in our <code>do</code>-block is returned automatically.</p>
<h3>Using the &#8216;or&#8217; operator</h3>
<p>I lied when I said that values can consist only of alphanumeric characters. Actually the web service specifications also allow the use of &#8220;+&#8221; and &#8220;-&#8220;, so we&#8217;ll need to add these to our parser. A nice way to achieve this is to use the <code>&lt;|&gt;</code>-operator that basically just means &#8220;or&#8221;:</p>
<aside>Function application is left-associative, so this won&#8217;t work: <code>print 1 + 2</code> as it would try to add <code>2</code> to the return value of <code>print 1</code>. You will need parentheses here: <code>print (1 + 2)</code>.</p>
</aside>
<pre><code class="language-haskell">value = do
    many1 (alphaNum &lt;|&gt; char '+' &lt;|&gt; char '-')
</code></pre>
<p>Another option would be to use <code>... &lt;|&gt; oneOf "+-"</code>.</p>
<p>With this out of the way we have everything we need to combine this parser with another parser that only expects a slash. The resulting parser will be used to read the parts of our URL (you remember: things delimited by slashes). For lack of a better name, let&#8217;s call it <code>part</code>.</p>
<pre><code class="language-haskell">part = do
    char '/'
    value
</code></pre>
<p>This does exactly what you might expect: It reads the character &#8220;/&#8221; and then a <code>value</code> as defined before.</p>
<h3>Failing gracefully</h3>
<p>I mentioned earlier that parser functions either return the value or fail. In most imperative programming languages, failing usually means that an error or exception will be thrown. Our parsers work a bit differently: Haskell has a special type called <code>Either</code> that represents values with two possibilities called <code>Left</code> and <code>Right</code>. By convention, <code>Left</code> is used to hold an error value and <code>Right</code> is used to hold a correct value. You&#8217;ll see in a minute how that looks.</p>
<p>Let&#8217;s confirm in Haskell&#8217;s REPL that our parsers work. For this we&#8217;ll use the <code>parse</code> helper function that expects the following parameters: the parser to execute, a context name (that we&#8217;ll just leave empty) and the input string.</p>
<pre><code>&gt; parse part "" "/foo+bar-42"
Right "foo+bar-42"

&gt; parse part "" "quux"
Left (line 1, column 1):
unexpected "q"
expecting "/"
</code></pre>
<p>The results should be self-explanatory: The first parser succeeded, returning a <code>Right</code> with the parsed string. The second call failed, returning a <code>Left</code> with a detailed error message.</p>
<h3>Some real work: Parsing strings and optionals</h3>
<p>Now let&#8217;s start to do some real work and write a parser that reads the first part of the URL including the country code and return that. The protocol can be either &#8220;http&#8221; or &#8220;https&#8221;, so we need to take care of both options, for the rest we can reuse our <code>part</code>-parser.</p>
<p>This parser introduces two new predefined parsers: <code>string</code>, which reads any given string (as opposed to <code>char</code> that only reads a single character) and <code>optional</code> that (surprise!) marks a parser as optional.</p>
<pre><code class="language-haskell">country = do
    string "http"
    optional (char 's')
    string "://example.org"
    part
</code></pre>
<p>In action:</p>
<pre><code>&gt; parse country "" "https://example.org/de/otherStuff"
Right "de"

&gt; parse country "" "http://not-the-example.org/de"
Left (line 1, column 5):
unexpected "n"
expecting "://example.org"
</code></pre>
<h3>Parsing delimited lists</h3>
<p>We&#8217;ll skip the vehicle part for now and implement the parsers for the car customization first. Options, accessories and packs are all quite similar: a key followed by a slash and a comma separated list of values. Let&#8217;s start with an interesting parser: <code>sepBy</code> splits a string using a separator and returns the results. The output won&#8217;t be a string now, but a list of strings instead:</p>
<pre><code class="language-haskell">commaDelimited = do
    sepBy value (char ',')
</code></pre>
<p>In the REPL this looks like this:</p>
<pre><code>&gt; parse commaDelimited "" "1,2,3,4"
Right ["1","2","3","4"]
</code></pre>
<p>The rest is easy:</p>
<pre><code class="language-haskell">packs = do
    string "/packs/"
    commaDelimited

options = do
    string "/options/"
    commaDelimited

accessories = do
    string "/accessories/"
    commaDelimited
</code></pre>
<h3>Looking ahead</h3>
<p>With that out-of-the-way we can concentrate on the most interesting part now: The vehicle information that can consist of one or more <code>part</code>s. Let&#8217;s start with a quite naive approach:</p>
<pre><code class="language-haskell">vehicle = do
    string "/vehicle"
    many1 part
</code></pre>
<p>This will obviously not work as it will read beyond the vehicle information and into the customization:</p>
<pre><code>&gt; parse vehicle "" "/vehicle/ford/prefect/packs/pack307"
Right ["ford","prefect","packs","pack307"]
</code></pre>
<p>We need a way to tell the parser where to stop. That can be done with the <code>manyTill</code> parser that runs a parser until another parser matches. If we want to check for more than one parser, we can use <code>choice</code> which expects a list of parsers and tries them consecutively. The problem is that parsers works greedily &#8211; so any character that matches a parser and is therefor already consumed stays consumed, even if the parser should eventually fail. We can avoid this by using <code>try</code> which makes the parser only consume input when it&#8217;s fully executed.</p>
<p>The tricky part is: We don&#8217;t want that either. We only want to check, <em>if</em> a parser will succeed, but not actually consume anything. The <code>lookAhead</code> parser does exactly that.</p>
<pre><code class="language-haskell">customization = do
    choice [try packs, try accessories, try options]

vehicle = do
    string "/vehicle"
    manyTill part (lookAhead customization)
</code></pre>
<p>This will first expect the string &#8220;/vehicle&#8221; and then run the <code>part</code> parser for as long as possible until our <code>customization</code> parser succeeds, but it will only consume the results of <code>part</code>.</p>
<h3>Skipping the rest</h3>
<p>That&#8217;s it, we don&#8217;t need the rest (<code>skipMany</code>), but we should still consume it.</p>
<pre><code class="language-haskell">theRest = do
    skipMany anyChar
</code></pre>
<h3>Returning more than one result</h3>
<p>We just created all the building blocks we need to parse the url, but we have to combine them. Up to this point, all parsers did something and returned the last result <em>after</em> running all parsers. What if we want the results of <em>all</em> parsers, i.e. the in-betweens?</p>
<p>Let&#8217;s take a step back first and write a parser that reads <em>exactly two</em> alphanumeric characters and then expects the input to end (<code>eof</code>):</p>
<pre><code class="language-haskell">twoChars = do
    alphaNum
    alphaNum
    eof
</code></pre>
<pre><code>&gt; parse twoChars "" "xy"
Right 'y'
</code></pre>
<p>That&#8217;s nice, but how do we get to the first <code>x</code>? As each parser returns a result itself, we can just pull it out and store it in a variable using the left arrow <code>&lt;-</code> and return a tuple containing all variables. You don&#8217;t have to return a tuple, you can return whatever data type holds your values and matches your domain.</p>
<pre><code class="language-haskell">twoChars = do
    x &lt;- alphaNum
    y &lt;- alphaNum
    eof
    return (x, y)
</code></pre>
<aside>You might remember me writing that the last line is always returned automatically, so what is this explicit <code>return</code> doing there? In Haskell, <code>return</code> doesn&#8217;t work like return in most languages: it takes a value and wraps it in a context.</p>
<p>If you actually want to know what&#8217;s going on, I can recommend the excellent book <a href="http://learnyouahaskell.com/">Learn You a Haskell For Great Good</a> by Miran Lipovača. If you&#8217;re just here for the parsers, please just ignore it.</p>
</aside>
<h3>Integrating everything</h3>
<p>Wrapping it all up, here&#8217;s our complete parser.</p>
<pre><code class="language-haskell">parser = do
    c  &lt;- country
    v  &lt;- vehicle
    cs &lt;- many1 customization
    theRest
    eof
    return (c, v, cs)
</code></pre>
<p>Taking it for a test run:</p>
<pre><code>&gt; parse parser "" "https://example.org/de/vehicle/trabant/5-doors/0815+universal/options/1,4711,815/packs/p7/accessories/a,b,c/width/1024/height/768/exterior-45.jpg"

Right ("de",["trabant","5-doors","0815+universal"],[["1","4711","815"],["p7"],["a","b","c"]])
</code></pre>
<p>Nice.</p>
<h2>Conclusion</h2>
<p>We just wrote a very maintainable parser in less than 40 lines of very readable code. To achieve this, we wrote small and comprehensible parsing functions that we combined to larger parsers.</p>
<p>Nothing we parsed was very impressive or particularly complex and a few loops combined with regular expressions could have achieved the same with maybe even less code. But as soon as a certain complexity is exceeded, the specification is prone to changes, or you want to create cleaner, more testable code that is actually re-usable, parser combinators can be a great alternative.</p>
<p>You can find the complete source (including type annotations) of the parser here: <a href="https://gist.github.com/cvk77/244bcdf7eb4f0f049221">parser.hs</a>.</p>
<h2>What&#8217;s next?</h2>
<p>This barely touches the surface of what Parsec is able to do. If you&#8217;re interesting in learning more, an excellent starting point is chapter 16 of <a href="http://book.realworldhaskell.org/read/using-parsec.html">Real World Haskell</a> by Bryan O&#8217;Sullivan, Don Stewart, and John Goerzen. It goes into much more detail, but expects quite a bit of Haskell knowledge. Also you can <a href="https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours/Parsing">Write yourself a Scheme in 48 Hours</a> using Parsec.</p>
<p>If you want to understand parser combinators in general, not necessarily only the Parsec library, check out Graham Hutton&#8217;s great book <a href="http://www.cs.nott.ac.uk/~pszgmh/book.html">Programming in Haskell</a>. Erik Meijers <a href="https://courses.edx.org/courses/DelftX/FP101x/3T2014/">functional programming MOOC at edX</a> also covers the topic, closely following Hutton&#8217;s book.</p>
<p>As mentioned earlier, there are parser combinator libraries for many languages, here&#8217;s a short and by no means complete list:<br />
* <a href="https://github.com/jparsec/jparsec">JParsec</a> for Java<br />
* <a href="http://www.quanttec.com/fparsec/">FParsec</a> for F#<br />
* <a href="http://pyparsing.wikispaces.com/">PyParsing</a> for Python</p>
<p>If you want to know more about the details of the <code>do</code>-notation and <code>return</code>-stuff or just impress your friends with <a href="https://wiki.haskell.org/Zygohistomorphic_prepromorphisms">Zygohistomorphic prepromorphisms</a>, <a href="http://learnyouahaskell.com/">Learn You A Haskell</a> is an excellent start. At the time of writing, <a href="https://twitter.com/bitemyapp">Chris Allen</a> and <a href="https://twitter.com/argumatronic">Julie Moronuki</a> are about 90% done with their <a href="http://haskellbook.com/">Haskell Book</a>. I&#8217;m sure it will be awesome.</p>
<hr>
<p><small>The image <a href="https://flic.kr/p/cAcNYU">Legos</a> by <a href="https://www.flickr.com/photos/8660423@N08/">qrevolution</a> is licensed under the Creative Commons Attribution 2.0 Generic (CC BY 2.0) licence.</small></p>The post <a href="https://www.webrunners.de/en/how-to-write-cleaner-parsing-code/">How to write cleaner parsing code</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Django CMS: Permission pitfalls</title>
		<link>https://www.webrunners.de/en/django-cms-permission-pitfalls/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=django-cms-permission-pitfalls</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Tue, 08 Sep 2015 14:11:38 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=372</guid>

					<description><![CDATA[<p>On my latest journey through the lands of Django CMS, I struggled with some permission issues. While Django CMS is convenient and a good CMS choice in general, it turns out to have some inconsistencies buried in the permission system. My scenario The requirements I have for the permission system in my current project are: [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/django-cms-permission-pitfalls/">Django CMS: Permission pitfalls</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>On my latest journey through the lands of Django CMS, I struggled with some permission issues.<br />
While Django CMS is convenient and a good CMS choice in general, it turns out to have some inconsistencies buried in the permission system.</p>
<h2>My scenario</h2>
<p>The requirements I have for the permission system in my current project are:</p>
<ul>
<li>All CMS pages should be available only for authenticated users</li>
<li>Editing shall only be allowed for staff</li>
<li>Some pages should be only visible to a certain group</li>
</ul>
<p>These requirements are somehow basic, right?</p>
<p><span id="more-372"></span></p>
<h2>Django CMS&#8217; places to set permissions</h2>
<p>Since Django CMS has a lot of different places where you can set permissions I&#8217;ll go through them step by step.</p>
<h3>&#8220;Login required&#8221; in page permissions</h3>
<p>There is a useful flag in the page permission form which enables to restrict view-access to the page for logged in users. In my opinion, there are two issues with that:</p>
<p>First, it interferes with the group- and user-based settings. I think it would be better to integrate authenticated users into the &#8220;View restrictions&#8221; section. Currently, it&#8217;s hard to tell which to use when.<br />
Secondly, user- and group based settings are applicable also for child pages, while &#8220;Login required&#8221; is not, which is inconsistent.</p>
<h3>Django CMS setting: CMS_PUBLIC_FOR</h3>
<p>The CMS setting <code>CMS_PUBLIC_FOR</code> offers the <a href="http://django-cms.readthedocs.org/en/latest/topics/permissions.html#view-restrictions">following feature</a> when set to <code>"staff"</code>:</p>
<blockquote><p>If the user accesses a page which does not have a view restriction, deny access, if he&#8217;s not staff.</p></blockquote>
<p>If set to <code>"all"</code> it works like:</p>
<blockquote><p>If the user accesses a page which does not have a view restriction, show it even if he&#8217;s anonymous.</p></blockquote>
<p>That&#8217;s nice, but there is no</p>
<blockquote><p>If the user accesses a page which does not have a view restriction, force him to login, if he&#8217;s not authenticated.</p></blockquote>
<p>That feature would be basically needed to use of Django CMS as an intranet application out-of-the-box.</p>
<h3>Users (page) / User groups (page)</h3>
<p>As stated in <a href="http://django-cms.readthedocs.org/en/latest/topics/permissions.html#users-page-user-groups-page">the documentation</a>, you can &#8220;easily add users with permissions over CMS page&#8221;. The following paragraph says:</p>
<blockquote><p>&#8220;You would be able to create a user with the same set of permissions using the usual Auth.User model, but using Users (page) is more convenient.&#8221;</p></blockquote>
<p>Actually this seems to be the wrong way to go. Django has perfect tools for creating users &#8211; why create another one, and even choose another name for it? This leads to confusion for staff and admins and should be removed.<br />
For &#8220;User groups (page)&#8221; I can hardly tell, because it&#8217;s not fully clear what it does: It seems to be a mix of global page permissions and some special user CRUD functionality. In the documentation you find:</p>
<blockquote><p>&#8220;User groups (page) manages the same feature on the group level.&#8221;</p></blockquote>
<p>But this is either confusing or wrong: The group management form has completely other functionality than the user management form. Since there is no further documentation, this feature is somehow useless for me.</p>
<h3>Global page permissions</h3>
<p>Setting <a href="http://django-cms.readthedocs.org/en/latest/topics/permissions.html#pages-global-permissions">global page permissions</a> gives a certain user or group permissions for all pages. The documentation is pretty poor, but in general, it&#8217;s self explaining how it works. It&#8217;s a useful feature if you have requirements like &#8220;Editors should be able to create pages, but not delete them.&#8221; The only problem here is that the global declaration overwrites permissions on page level &#8211; this is something I&#8217;d not expect.</p>
<h3>Django permission: &#8220;Can view page&#8221;</h3>
<p>Another setting that overwrites page-level permission is the Django permission &#8220;Can view page&#8221;: If this is set for a user or a user group, the page-level settings are also ignored.</p>
<h2>How I solved my requirements</h2>
<p>First I wrote a <a href="https://gist.github.com/schneck/062946b0592c35bb38e4">custom middleware</a> that redirects all requests to Django CMS pages to the login. Then, I removed the &#8220;can view pages&#8221; permission from all groups and all global permissions for non-staff.</p>
<p>Finally I removed all view restrictions on the page root and set them only on the particular pages which should be restricted.</p>
<h2>Summary</h2>
<p>My two major findings which seem to be worth a discussion are:</p>
<blockquote><p>If you give a user or group the Django CMS permission to view restricted pages on a global level, this setting overwrites all page-level restrictions.</p></blockquote>
<blockquote><p>If you give a user or group the Django permission &#8220;can view page&#8221;, this setting overwrites all page-level restrictions.</p></blockquote>
<p>I think the permission capabilities of Django CMS are great in general, but they follow a false principle when the global rule overwrites the special one; it&#8217;s just not intuitive.</p>
<p>If you find something I overlooked, I&#8217;d be happy to discuss!</p>The post <a href="https://www.webrunners.de/en/django-cms-permission-pitfalls/">Django CMS: Permission pitfalls</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Software and code quality</title>
		<link>https://www.webrunners.de/en/software-and-code-quality-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=software-and-code-quality-2</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Fri, 04 Sep 2015 08:48:15 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=346</guid>

					<description><![CDATA[<p>Software and code quality matters because it is directly related to maintainability and therefore to the costs for developing software systems, and for extending them with new features. Measuring and evaluating software and code quality objectively is a difficult task which is illustrated by the following quote in a funny way: The only valid measurement [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/software-and-code-quality-2/">Software and code quality</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>Software and code quality matters because it is directly related to maintainability and therefore to the costs for developing software systems, and for extending them with new features.</p>
<p>Measuring and evaluating software and code quality objectively is a difficult task which is illustrated by the following quote in a funny way:</p>
<blockquote><p>The only valid measurement of code quality is WTFs/minute<br />
&#8212; <cite><a href="http://www.osnews.com/story/19266/WTFs_m">Thom Holwerda</a></cite></p></blockquote>
<p>This implies that the only way to measure software quality is a subjective, individual and broad process. This is certainly true to some extend, but we believe that it is possible to apply concrete practices and methods to ensure a good software quality.<br />
<span id="more-346"></span></p>
<p>Since software quality is a topic that a whole series of books<sup id="fnref-346-cc"><a href="#fn-346-cc">1</a></sup> could be dedicated to, I just want to give a high level overview in this post.</p>
<h2>Definition of software quality</h2>
<p>If we want to evaluate <a href="https://en.wikipedia.org/wiki/Software_quality">software quality</a> it basically boils down to the question of how much the software meets the particular requirements that where specified for the software in question.</p>
<p>The requirements can be divided into two groups:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Functional_requirement">Functional requirements</a> (FR)
<ul>
<li>FRs define what the system is supposed to do</li>
</ul>
</li>
<li><a href="https://en.wikipedia.org/wiki/Non-functional_requirement">Non-functional requirements</a> (NFR)
<ul>
<li>Also called quality requirements</li>
<li>NFRs define how the system is supposed to be</li>
</ul>
</li>
</ul>
<h2>Software quality characteristics</h2>
<p>Some of the most important characteristics of software quality<sup id="fnref-346-iso9126"><a href="#fn-346-iso9126">2</a></sup> are:</p>
<ul>
<li>Functional correctness</li>
<li>Reliability</li>
<li>Usability
<ul>
<li>Adequacy</li>
<li>Learnability</li>
<li>Robustness</li>
</ul>
</li>
<li>Maintainability
<ul>
<li>Readability</li>
<li>Evolvability</li>
<li>Testability</li>
</ul>
</li>
<li>Efficiency</li>
<li>Portability</li>
<li>Security</li>
</ul>
<p>Functional correctness is a related to the functional requirements. All other aspects tend to be more related to the non-functional requirements.</p>
<h3>Functional correctness</h3>
<p>A software is considered correct when it meets all the functional requirement.</p>
<h3>Reliability</h3>
<p>[latex]Reliability = Correctness + Availability[/latex]</p>
<p>Availability of a software system is the percentage of time where the system is fully operational.</p>
<p>Availability ([latex]A[/latex])is defined as:</p>
<p>[latex]A = frac{MTBF}{MTBF + MTTR}[/latex]</p>
<p>([latex]MTBF[/latex]: mean time between failure, [latex]MTTR[/latex]: mean time to repair)</p>
<h3>Usability</h3>
<p>The usability describes the ease of use of a software and is defined by adequacy, learnability and robustness.</p>
<p>Adequacy means that</p>
<ol>
<li>the user input</li>
<li>the program execution</li>
<li>the result of the program execution</li>
</ol>
<p>are reasonable for the given task.</p>
<p>The learnability of a software is influenced by the documentation and by the user interface which should provide efficient use of functionality.</p>
<p>A software is considered robust if the consequences of defect are inversely proportional to the probability of occurrence of the defect.</p>
<h3>Maintainability</h3>
<p>A software is considered maintainable if</p>
<ul>
<li>defects and their cause can be isolated easily</li>
<li>defects can be fixed easily</li>
<li>changes can be made easily</li>
<li>extensions can be made easily</li>
</ul>
<p>Evolvability is defined as the capability of a system to be extended with new features.</p>
<p>Therefore maintainability is closely related to readability, evolvability, and testability of the code.</p>
<h3>Efficiency</h3>
<p>Efficient software emphasizes a careful use of resources like e.g. CPU, RAM or external (secondary) storage. Efficiency is not to be mixed up with product efficiency. The product efficiency of a software system is related to the investment of time and money.</p>
<h3>Portability</h3>
<p>The portability describes how easy it is to port the program to another platform or device.</p>
<p>A software is considered to be portable if the changes that have to be made to the system to run on another device or operating system are less expensive than reimplementation.</p>
<h3>Security</h3>
<p>The security of a software is partly related to the requirements as security concerns should be part of the functional requirements for the system in question. Besides that security is also related to defects and design flaws which can be minimized by a good code quality and software architecture. There are tools which can help finding security issues like e.g. penetration testing tools.</p>
<p>Here are some aspects that have to be considered for good security:</p>
<ul>
<li>Authorization</li>
<li>Encryption</li>
<li>Handling passwords</li>
<li>Session management</li>
<li>Validation</li>
<li>Preventing SQL injection</li>
</ul>
<h2>Clean Code Developer</h2>
<p><a href="http://clean-code-developer.de/">Clean Code Developer</a> (CCD) is an initiative that promotes software quality and the cultivation of higher professionalism within the software industry.</p>
<p>CCD defines four main values:</p>
<ul>
<li>Evolvability</li>
<li>Correctness</li>
<li>Product efficiency</li>
<li>Continuous improvement</li>
</ul>
<p>From these values the CCD initiative derives a hierarchy of principles, patterns and tools that support the values and that are divided into different skill levels.</p>
<p>Evolvability and correctness have already been defined above.</p>
<h3>Product efficiency</h3>
<p>Product efficiency is influenced by the time and the costs for developing a software system. A software system is considered to be (product) efficient when the investment of time and money is reasonable low. Product efficiency should not be mixed up with efficiency as defined earlier.</p>
<h3>Continuous improvement</h3>
<p>Continuous improvement is not a software quality characteristic. However, in order to keep the software quality high, it is important for software development teams to make reviews and retrospectives.</p>
<h2>Maintainability is crucial</h2>
<p>While all the characteristics described above are important, maintainability is crucial. If the code base is messy, it will significantly slow down the development process. Introducing new features will be expensive because they are hard to weave in. Throwing more staff at the project will only result in a growing mess and productivity yet decreases. This scenario is described in Robert C. Martin book <a href="https://books.google.de/books?id=dwSfGQAACAAJ&amp;hl=de">Clean Code</a>. He calls it &#8220;the total cost of owning a mess&#8221;. The cost is that productivity will tend to drive towards zero over time.</p>
<p><img decoding="async" title="The total cost of owning a mess" src="http://blog.webrunners.de/wp-content/uploads/2015/09/productivity.svg" alt="alt text"></p>
<h2>Methods and practices</h2>
<p>Software engineering practices and methods have great influence on the level of software quality. Some of the most important are:</p>
<ul>
<li>Agile software development</li>
<li>Domain driven design</li>
<li>Type driven development</li>
<li>Iterative software development</li>
<li>Code reviews</li>
<li>TDD</li>
<li>Refactoring</li>
<li>Automated testing</li>
<li>Continuous integration</li>
<li>Issue tracking</li>
<li>Source code conventions</li>
<li>Penetration testing</li>
</ul>
<h2>Design principles</h2>
<p>Here is a set of design principles that are closely related to high maintainability:</p>
<ul>
<li>Don&#8217;t repeat yourself (DRY)</li>
<li>Keep it simple stupid (KISS)</li>
<li>SOLID principles
<ul>
<li>Single responsibility principle (SRP)</li>
<li>Open closed principle (OCP)</li>
<li>Liskov substitution principle (LSP)</li>
<li>Interface segregation principle (ISP)</li>
<li>Dependency inversion principle (DIP)</li>
</ul>
</li>
<li>Separation of concerns (SoC)</li>
<li>Favor composition over inheritance (FCoI)</li>
<li>You ain&#8217;t gonna need it (YAGNI)</li>
</ul>
<h2>Metrics</h2>
<p>In order to find a starting point for improvement of quality and maintainability of the code, it can be valuable to examine some code metrics.</p>
<p>The most important code metrics are:</p>
<ul>
<li>Lack of cohesion of methods (LCOM)</li>
<li>Afferent and efferent coupling (Ca, Ce)</li>
<li>Cyclomatic complexity (CC)</li>
<li>Lines of code (LOC)</li>
<li>Number of methods / fields per class (NbMethods, NbFields)</li>
<li>Abstractness (A)</li>
<li>Instability (I)</li>
<li>Distance from the main sequence (D)</li>
</ul>
<p>There are several tools for deriving those metrics like NDepend (.NET) or Sonar (Java).</p>
<h2>Software Tests</h2>
<p>For good software quality it is essential to have a good testing strategy which should include:</p>
<ul>
<li>Unit tests</li>
<li>Integration tests</li>
<li>System tests</li>
<li>Regression tests</li>
</ul>
<p>There are tools that help with testing like</p>
<ul>
<li>Unit testing frameworks</li>
<li>Mocking frameworks</li>
<li>Test coverage tools</li>
</ul>
<h2>Additional concerns</h2>
<h3>Make invalid state unrepresentable</h3>
<p>Making invalid state unrepresentable is a very valuable way to make a software maintainable, testable and robust. Here is an example of a poor type design:</p>
<pre><code class="csharp">public class Contact
{
  public string FirstName { get; set; }
  public string MiddleName { get; set; }
  public string LastName { get; set; }

  public string EmailAddress { get; set; }
  public bool IsEmailVerified { get; set; }
}
</code></pre>
<p>If this was a domain model from the business layer, then there are several problems. It is not clear</p>
<ul>
<li>which values are optional / required</li>
<li>what the constraints are</li>
<li>which fields are linked together</li>
<li>what the domain logic is</li>
</ul>
<p>E.g. possible invalid states would be, all fields are NULL, <code>EmailAddress</code> is NULL and <code>IsEmailVerified</code> is true, last name is missing, etc.</p>
<p>These problems can be solved by a good <a href="http://fsharpforfunandprofit.com/series/designing-with-types.html">design of the types</a>, which will improve the software quality a great deal.</p>
<h3>The problem with NULL</h3>
<p>Even though most software developers got very much used to it NULL is a problem. In <a href="https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/">this post</a> the author describes how NULL</p>
<ul>
<li>subverts types</li>
<li>is sloppy</li>
<li>is a special case</li>
<li>makes poor APIs</li>
<li>exacerbates poor language decisions</li>
<li>is difficult to debug</li>
<li>is non-composable</li>
</ul>
<p>Software quality can be improved by choosing a language that does not know NULL like e.g. F# or Haskell.</p>
<h3>The problem with state</h3>
<p>Managing state can become complex very easily. When passing a mutable object to a function, it can potentially be changed by that function. The function signature might or might not imply this. Anyway, there is no way to be sure that the object won&#8217;t be changed. If the object is passed to many functions from many different modules, it will become very hard to keep track.</p>
<p>If state is even mutated from different threads it becomes even more difficult. Using locks is only a poor workaround that results in more complex and less maintainable code.</p>
<p>Here immutability comes to the rescue. Some languages support immutable data structures by default as e.g. F#, Haskell, Clojure and other functional programming languages.</p>
<p>With immutable data structures it is much easier to reason about the correctness of the code. Because of <a href="https://wiki.haskell.org/Referential_transparency">referential transparency</a> there can&#8217;t be implicit side effects<sup id="fnref-346-se"><a href="#fn-346-se">3</a></sup>. The order of function calls doesn&#8217;t matter and the code becomes much more predictable. Less tests are needed because functions can be tested in isolation. We do not have to test a function in the context of all possible or potential system states which will result in a better product efficiency.</p>
<p>Also concurrency is much simpler because we do not have to worry about concurrent updates.</p>
<h3>The programming language</h3>
<p>Also the choice of programming language can affect the quality of the software. The following language features can improve code quality and product efficiency:</p>
<ul>
<li>A good type system</li>
<li>Type inference</li>
<li>Concise syntax</li>
<li>Pattern matching</li>
<li>Immutability by default</li>
<li>Structural equality by default</li>
<li>Scriptability</li>
<li>Ability for rapid prototyping</li>
</ul>
<h3>A closer look at dependencies</h3>
<p>Visualizations of the dependencies between types in a software system can be a good measure for quality besides code metrics. <a href="http://fsharpforfunandprofit.com/posts/cycles-and-modularity-in-the-wild/">In this article</a> the author presents some interesting examples.</p>
<p>Here are two graphs of the two libraries <a href="http://www.specflow.org/">SpecFlow</a> and <a href="https://tickspec.codeplex.com/">TickSpec</a> which both have a similar sized feature set.</p>
<p><strong>SpecFlow:</strong><br />
<img decoding="async" title="SpecFlow" src="http://fsharpforfunandprofit.com/assets/svg/specFlow.all.dot.svg" alt="alt text"><sup id="fnref-346-specflow"><a href="#fn-346-specflow">4</a></sup></p>
<p><strong>TrickSpec:</strong><br />
<img decoding="async" title="TrickSpec" src="http://fsharpforfunandprofit.com/assets/svg/tickSpec.all.dot.svg" alt="alt text"><sup id="fnref-346-trickspec"><a href="#fn-346-trickspec">5</a></sup></p>
<p>The author argues that the complexity of the code is closely related to the programming language. TrickSpec was implemented in F# and shows a clear and clean dependency graph. On the other hand SpecFlow is a well designed library in C#, but still might be more difficult to maintain because of the more complex dependencies.</p>
<h2>Conclusion</h2>
<p>Software quality is an important but complex concern.</p>
<p>You can see this post as a broad summary of the topic. It can serve as a starting point, a check list, or a guide line when you make considerations about software quality.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Software_quality">Software quality</a></li>
<li><a href="http://clean-code-developer.de/">Clean Code Developer</a></li>
<li><a href="http://fsharpforfunandprofit.com/series/designing-with-types.html">Design with types</a></li>
<li><a href="https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/">The worst mistake of computer science</a></li>
<li><a href="http://fsharpforfunandprofit.com/posts/cycles-and-modularity-in-the-wild/">Cycles and modularity in the wild</a></li>
<li><a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">Principles of OOD</a></li>
<li><a href="http://fsharpforfunandprofit.com/posts/correctness-immutability/">Immutability</a></li>
</ul>
<hr>
<p><small>The <a href="https://images.unsplash.com/photo-1429051883746-afd9d56fbdaf?q=80&amp;fm=jpg&amp;s=b5bc5b301b282fd18c85d9bb6ef941e6">header image</a> by <a href="https://unsplash.com/negativespace">Luis Llerena</a> is licensed under a <a href="https://unsplash.com/license">UNSPLASH LICENSE</a>. The picture was modified to fit this article.</small></p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-346-cc"><a href="https://books.google.de/books?id=dwSfGQAACAAJ&amp;hl=de">Clean Code</a>&nbsp;<a href="#fnref-346-cc">↩</a></li>
<li id="fn-346-iso9126"><a href="https://en.wikipedia.org/wiki/ISO/IEC_9126">ISO/IEC 9126 Software engineering — Product quality</a>&nbsp;<a href="#fnref-346-iso9126">↩</a></li>
<li id="fn-346-se">Note that <em>side effects</em> in this context refers to the object(s) passed to a function. This disregards other side effects like database updates, console outputs, sending emails, etc.&nbsp;<a href="#fnref-346-se">↩</a></li>
<li id="fn-346-specflow">The SpecFlow dependency graph by <a href="http://fsharpforfunandprofit.com/">Scott Wlaschin</a> is licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC-BY-NC</a>.&nbsp;<a href="#fnref-346-specflow">↩</a></li>
<li id="fn-346-trickspec">The TrickSpec dependency graph by <a href="http://fsharpforfunandprofit.com/">Scott Wlaschin</a> is licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC-BY-NC</a>.&nbsp;<a href="#fnref-346-trickspec">↩</a></li>
</ol>
</div>The post <a href="https://www.webrunners.de/en/software-and-code-quality-2/">Software and code quality</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Remote logging</title>
		<link>https://www.webrunners.de/en/remote-logging/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=remote-logging</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Tue, 11 Aug 2015 08:42:28 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=266</guid>

					<description><![CDATA[<p>1 Reading Time: 15min What this is about Secure and reliable syslog remote logging Free yourself from receiving hundreds of logging emails each day Setup email alerts Log server I assume we all have an understanding what logging is and why logging matters. What we want is a centralized place where all log messages can [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/remote-logging/">Remote logging</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<hr />
<p><sup id="fnref-266-him"><a href="#fn-266-him" rel="footnote">1</a></sup></p>
<p>Reading Time: 15min</p>
<h3>What this is about</h3>
<ul>
<li>Secure and reliable <em>syslog</em> remote logging</li>
<li>Free yourself from receiving hundreds of logging emails each day</li>
<li>Setup email alerts<br />
<span id="more-266"></span></li>
</ul>
<h3>Log server</h3>
<p>I assume we all have an understanding what logging is and why logging matters.<br />
What we want is a centralized place where all log messages can be sent to, where they are analysed and can trigger alerts.<br />
There is a big picture you can get over long-term logging, called Data-Mining<sup id="fnref-266-dam"><a href="#fn-266-dam" rel="footnote">2</a></sup> and which is out of scope for this article.</p>
<p>The first problem I repeatedly faced was how to collect all logging messages securely in a central place. Of course rsyslog can manage it, but has its own pitfalls and doesn&#8217;t allow instant further processing.<br />
Logstash<sup id="fnref-266-lgs"><a href="#fn-266-lgs" rel="footnote">3</a></sup>, written in Java, and logstash-forwarder, written in the Go language, came to the rescue.</p>
<h3>Logstash-forwarder, Logstash, Graylog2, Elasticsearch, Kibana.</h3>
<p><img loading="lazy" decoding="async" style="float: left; padding: 0 20px 20px 0;" src="https://www.webrunners.de/wp-content/uploads/2015/08/logflow.jpg" alt="logflow" width="270" height="240" />What a chain of tools. Logstash-forwarder (shipper), Logstash (server/filter), Elasticsearch (database) and Kibana (frontend) seem to be an obvious choice, since &#8220;brought together&#8221; by Elasticsearch in 2013<sup id="fnref-266-els"><a href="#fn-266-els" rel="footnote">4</a></sup>.<br />
Graylog2 (server/filter/frontend) is a different project from Germany that seems to have a lot in common, but on the other hand has some frontend features that are missing in Kibana.</p>
<p>Logstash-forwarder uses the Lumberjack-protocol that should not be mixed up with the &#8220;Project Lumberjack&#8221;<sup id="fnref-266-plm"><a href="#fn-266-plm" rel="footnote">5</a></sup>, based on the work of the CEE: Common Event Expression<sup id="fnref-266-main"><a href="#fn-266-main" rel="footnote">6</a></sup>.</p>
<blockquote><p>CEE is a sort of comedic tragedy of design</p></blockquote>
<p>&#8212; Jordan Sissel, developer of Logstash and logstash-forwarder<sup id="fnref-266-sis1"><a href="#fn-266-sis1" rel="footnote">7</a></sup>.</p>
<p>I can only guess why he named his own protocol Lumberjack, but the name seems to be a great fit<sup id="fnref-266-ref1"><a href="#fn-266-ref1" rel="footnote">8</a></sup>/<sup id="fnref-266-ref2"><a href="#fn-266-ref2" rel="footnote">9</a></sup> and also a parody of the Monty Python skit &#8220;Lumberjack Song&#8221;<sup id="fnref-266-sis2"><a href="#fn-266-sis2" rel="footnote">10</a></sup>.</p>
<blockquote><p>The lumberjack protocol used by this project exists to provide a network protocol for transmission that is secure, low latency, low resource usage, and reliable.</p></blockquote>
<p>&#8212; Jordan Sissel about logstash-forwarder<sup id="fnref-266-sis3"><a href="#fn-266-sis3" rel="footnote">11</a></sup></p>
<p>Logstash-forwarder takes files or stdout as input stream. Then it provides it securely and reliable to Logstash, which does further processing. This is exactly what we need, as all applications already write log-files. With Logstash alone we would have plenty of choices for other input formats. For the task of remotely collecting syslog files, the so called &#8220;lumberjack-input&#8221; suffices, as it is the service that logstash-forwarder connects to.</p>
<h3>Forward and process</h3>
<p>Logstash-forwarder is sending the syslog file, tagging it as syslog type. Besides the server and SSL-cert configuration, it&#8217;s configuration has only a &#8220;files&#8221;-block, indicating what it is supposed to send to the Logstash server:</p>
<pre>"files":[
 {
 "paths":[
 "/var/log/syslog"
 ],
 "fields": { "type": "syslog" }
 }
]</pre>
<p>Now we have a lightweight shipper on each host, sending logfiles to our logserver, where we have Logstash and its more heavy requirements Java and Elasticsearch installed. As a frontend view on Elasticsearch, we also have Kibana<sup id="fnref-266-kib"><a href="#fn-266-kib" rel="footnote">12</a></sup> in place.</p>
<p>Focusing on Logstash, it collects all messages forwarded by the shipper (logstash-forwarder) and outputs everything to the database (Elasticsearch) for later review (Kibana).</p>
<p>The main configuration for Logstash is also very simple.</p>
<p>Have an input:</p>
<pre>input {
 lumberjack {
 port =&gt; 5000
 ssl_certificate =&gt; "path"
 ssl_key =&gt; "path"
 }
}</pre>
<p>Have an output:</p>
<pre>output {
 elasticsearch { host =&gt; localhost }
}</pre>
<p>Anything that arrives via logstash-forwarder, will be stored to Elasticsearch.<br />
With Elasticsearch&#8217;s query language, we have the possibility to search and filter very quickly, to build exactly the view that helps us identifying/analysing problems.<br />
This leads to the questions what to search for, or in other words: How is our data structured?<br />
The next big problem with logging is that most applications have their own log-message standard. But we want to have it normalized. One simple definition of a log-message is:</p>
<p>&#8220;timestamp plus data&#8221; &#8211; Jordan Sissel<sup id="fnref-266-sis4"><a href="#fn-266-sis4" rel="footnote">13</a></sup></p>
<p>That describes enough to have at least one timestamp field required.<br />
As logstash-forwarder just sends files line by line, we need a parser construct for Logstash to analyse the incoming data. Therefore Logstash has filters. A special one, we can use to parse the incoming syslog messages, is called &#8220;the grok filter&#8221;.<br />
The grok filter provides named regex-patterns to break up a complex regex for parsing a message line. I know this method a bit from fail2ban and am still wondering, if they have anyhow related roots.<br />
With the filter now in place, we extract a timestamp field and some other fields additionally to the base message and are then able to search within Elasticsearch more specifically.</p>
<pre>filter {
 if[type] == "syslog" {
 grok {
   match =&gt; { "message" =&gt; "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:[%{POSINT:syslog_pid}])?: %{GREEDYDATA:syslog_message}" }
 }
 date {
   match =&gt;[ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
 }
 }
}</pre>
<h3>Logs via email</h3>
<p>As every host is sending emails from applications or cronjobs to hostmaster, my mailbox was a pain to look at every morning. Now I forward everything to a special mailbox and parse it via Logstash, which can also trigger a simple alert.<br />
Later on, I will show how we made our setup using Graylog2, which provides alerts via streams over a web GUI.</p>
<h3>IMAP input</h3>
<p>As Logstash is already running, I only needed another input</p>
<pre>input {
 imap {
 host =&gt; "dns, or ip"
 password =&gt; "password"
 user =&gt; "login"
 type =&gt; "email"
 }
}</pre>
<p>Now every mail that arrives will be tagged as &#8220;email&#8221;, and has already been processed with a timestamp by the IMAP input.<br />
I want to have a simple alert, which sends me an email for every matched error. Logstash has a conditional expression:</p>
<pre>output {
 if[type] == "email" and[message] ~ /error/ {
 email {
 attachments =&gt;["message"]
 to =&gt; "email-address"
 }
 }
}</pre>
<p>Wow, that was easy. And there are also Logstash outputs to inform our Icinga, or send a note via &#8220;hipchat-output&#8221;.<br />
But now, imagine using the email alert for a series of logging messages. That could easily lead to hundreds of email alerts. We need a more sophisticated solution for this.</p>
<h3>Email alerts</h3>
<p>After having Graylog2<sup id="fnref-266-gry"><a href="#fn-266-gry" rel="footnote">14</a></sup> installed and configured on the same server Logstash is running, I only changed the output of Logstash to gelf:</p>
<pre>output {
 gelf { host =&gt; localhost }
}</pre>
<p>And now everything Logstash gets via inputs and parses via filters, arrives at Graylog2&#8217;s gelf-udp-input, which then has an Elasticsearch output again.</p>
<p>Why the heck this overhead? Because Logstash in combination with logstash-forwarder is great at sending messages securely, reliable and low resource. Also it has a lot pre-processing options.<br />
And Graylog2 is great in terms of alerts. I can now configure &#8220;streams&#8221; that are basically pattern-matched messages, and can trigger an pattern-matched email-alert.</p>
<p>What is the benefit over the Logstash email output?</p>
<ul>
<li>Graylog2 stream alerts can be paused after first trigger, leading to a much lower alerting rate</li>
<li>Graylog2 can manage users and permissions for streams that let me provide logs for a certain host to anybody using it, without showing everything</li>
<li>Graylog2 has a lot more to offer. E.g. looking promising with additional external dashboards specialized for deployments<sup id="fnref-266-gds"><a href="#fn-266-gds" rel="footnote">15</a></sup></li>
</ul>
<p>Additionally, I will keep using Kibana, because it has a much cleaner view on the whole index.</p>
<h3>Résumé</h3>
<p>With rsyslog forwarding I always duplicated all logs before processing them. Without logstash-forwarder it was a hassle to use logstash (overhead of Java, or rsyslog odysseys). Now logging is fun for me. Lightweight forwarder, secure transmission. The specs for the logserver are a bit heavy (6GB RAM), but as best practice advices, it could be clustered if required.</p>
<h3>Disclaimer</h3>
<p>I provide by no means a copy and paste ready configuration. You are in responsibility to understand missing requirements and side-effects.</p>
<h3>Resources</h3>
<div class="footnotes">
<hr />
<ol>
<li id="fn-266-him">The typewriter image by <a href="https://unsplash.com/szolkin">Sergei Zolkin</a> is licensed by <a href="https://unsplash.com/license">unsplash</a> under <a href="http://creativecommons.org/publicdomain/zero/1.0/">CC0 1.0</a>. The picture was modified to fit this article. <a href="#fnref-266-him" rev="footnote">↩</a></li>
<li id="fn-266-dam"><a href="https://en.wikipedia.org/wiki/Data_mining">https://en.wikipedia.org/wiki/Data_mining</a> <a href="#fnref-266-dam" rev="footnote">↩</a></li>
<li id="fn-266-lgs"><a href="https://www.elastic.co/products/logstash">https://www.elastic.co/products/logstash</a> <a href="#fnref-266-lgs" rev="footnote">↩</a></li>
<li id="fn-266-els"><a href="https://www.elastic.co/blog/welcome-jordan-logstash">https://www.elastic.co/blog/welcome-jordan-logstash</a> <a href="#fnref-266-els" rev="footnote">↩</a></li>
<li id="fn-266-plm"><a href="https://fedorahosted.org/lumberjack/">https://fedorahosted.org/lumberjack/</a> <a href="#fnref-266-plm" rev="footnote">↩</a></li>
<li id="fn-266-main"><a href="http://www.kuehnel.org/bachelor.pdf">http://www.kuehnel.org/bachelor.pdf</a> <a href="#fnref-266-main" rev="footnote">↩</a></li>
<li id="fn-266-sis1">http://www.semicomplete.com/blog/geekery/CEE-logging-for-profit.html <a href="#fnref-266-sis1" rev="footnote">↩</a></li>
<li id="fn-266-ref1"><a href="https://en.wikipedia.org/wiki/Lumberjack">https://en.wikipedia.org/wiki/Lumberjack</a> <a href="#fnref-266-ref1" rev="footnote">↩</a></li>
<li id="fn-266-ref2"><a href="https://en.wikipedia.org/wiki/Logging">https://en.wikipedia.org/wiki/Logging</a> <a href="#fnref-266-ref2" rev="footnote">↩</a></li>
<li id="fn-266-sis2"><a href="https://github.com/elastic/logstash-forwarder/issues/125">https://github.com/elastic/logstash-forwarder/issues/125</a> <a href="#fnref-266-sis2" rev="footnote">↩</a></li>
<li id="fn-266-sis3"><a href="https://github.com/elastic/logstash-forwarder/blob/master/README.md">https://github.com/elastic/logstash-forwarder/blob/master/README.md</a> <a href="#fnref-266-sis3" rev="footnote">↩</a></li>
<li id="fn-266-kib"><a href="https://www.elastic.co/products/kibana">https://www.elastic.co/products/Kibana</a> <a href="#fnref-266-kib" rev="footnote">↩</a></li>
<li id="fn-266-sis4"><a href="https://logstash.jira.com/browse/LOGSTASH-675">https://logstash.jira.com/browse/LOGSTASH-675</a> <a href="#fnref-266-sis4" rev="footnote">↩</a></li>
<li id="fn-266-gry"><a href="http://www.Graylog2.org/">http://www.Graylog2.org/</a> <a href="#fnref-266-gry" rev="footnote">↩</a></li>
<li id="fn-266-gds"><a href="http://docs.Graylog.org/en/1.1/pages/external_dashboards.html">http://docs.Graylog.org/en/1.1/pages/external_dashboards.html</a> <a href="#fnref-266-gds" rev="footnote">↩</a></li>
</ol>
</div>The post <a href="https://www.webrunners.de/en/remote-logging/">Remote logging</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Twitter with Rx</title>
		<link>https://www.webrunners.de/en/twitter-with-rx/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=twitter-with-rx</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Tue, 23 Jun 2015 12:56:27 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=174</guid>

					<description><![CDATA[<p>In this post we will look at another sample program to get to know a few more Rx operators. We will also see how Rx is great for dealing with user interactions combined with asynchronous data streams. Basically the program filters a stream of tweets by user input. There are two kinds of ongoing events [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/twitter-with-rx/">Twitter with Rx</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>In this post we will look at another sample program to get to know a few more Rx operators. We will also see how Rx is great for dealing with user interactions combined with asynchronous data streams.<br /><span id="more-174"></span></p>
<p>Basically the program filters a stream of tweets by user input. There are two kinds of ongoing events involved, user inputs and tweets incoming in real-time from Twitter. Here are some detailed specifications:</p>
<ol>
<li><strong>The user can type a search text into a search field</strong><br />When the user has entered at least 3 characters and stops typing for at least 2 second the text in the search field will be processed for a new search.</li>
<li><strong>User inputs will be used to filter the incoming tweets</strong><br />The tweets must contain an exact (but case-insensitive) match of the user input. The filtered tweets are displayed on the UI ordered from most recent (top of the list) to oldest (bottom of the list). Every time the item count of the list exceeds a maximum of 20 the oldest tweet is supposed to be removed.</li>
<li><strong>New tweets should be displayed with a sample rate of one second.</strong><br />Only a maximum of one tweet should be displayed per second. All other tweets should be dropped.</li>
<li><strong>When the search text is changed according to 1. the tweets should be filtered by the new text according to 2.</strong></li>
<li><strong>All filtered tweets are classified and sorted into different lists</strong><br />Based on the score provided by a classifier each tweet will be considered either as awesome or boring. A score greater than 1000 is considered to be awesome and a score equal or less than 1000 is considered to be boring. Awesome and boring tweets are displayed in separate lists.</li>
</ol>
<p>(The classifier function can be seen as a black box. In this sample it is a very stupid algorithm that just serves to demonstrate the capabilities of Rx. In another scenario we could imagine it to be some kind of machine learning algorithm or something like that.)</p>
<p>This is how the application&#8217;s simple UI will look like:</p>
<p><a href="https://www.webrunners.de/wp-content/uploads/2020/04/screenshot2.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-227 size-full" src="https://www.webrunners.de/wp-content/uploads/2015/06/schreenshot2.jpg" alt="schreenshot2" width="1196" height="798" /></a></p>
<p>The source code can be downloaded <a href="https://github.com/webrunners/rx-examples/tree/master/Twitter">here</a>.</p>
<h2>Implementation</h2>
<p>Now we will go through the requirements one by one and explore how they can be implemented using Rx.</p>
<h3>Handling user input</h3>
<p>To handle the user input we need to apply the Rx operators <code>Where</code> and <code>Throttle</code>.</p>
<h4>Where</h4>
<p><code>Where</code> is a filtering operator that filters an observable sequence based on a predicate function. In the diagram below only the result sequence only emits values that are greater than 2.</p>
<p>This can be used to filter out search texts with less than 3 characters.</p>
<h4>Throttle</h4>
<p>The filtering operator <code>Throttle</code> only emits an item from a source sequence when a given time span has passed without the source emitting any other items. In other words all items that are rapidly followed by other items are ignored.</p>
<p>In our application we can use this when the user is typing in characters. As long as he is rapidly typing no events will let through. But as soon as he stops for a given time span (in this case 2 seconds) an item from the source stream is emitted.</p>
<p>To convert the property that is bound to the view to an observable we can use <a href="https://gist.github.com/battermann/761dd277cb9c3812d6d5#file-notifypropertychangedextensions-cs">this</a> extension method as described <a href="http://blog.leifbattermann.de/2015/06/21/typesafe-conversion-of-viewmodel-property-to-observable-stream/">here</a>. Also we have to make sure that in the view the control’s data binding has an <code>UpdateSourceTrigger</code> that is set to <code>PropertyChanged</code>.</p>
<pre><code class="xml">&lt;TextBox Text="{Binding Input, UpdateSourceTrigger=PropertyChanged}"/&gt;
</code></pre>
<p>Then we can use this code to create the observable sequence of search text inputs:</p>
<pre><code class="language-csharp">var searchTexts = this
    .ToObservable(() =&gt; SearchTextBox)
    .Throttle(TimeSpan.FromSeconds(2))
    .Where(x =&gt; x.Length &gt; 2);
</code></pre>
<p>If we subscribe to this observable by adding all items to a list the output might be something like this:</p>
<p><a href="https://www.webrunners.de/wp-content/uploads/2020/04/screenshot1.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-225 size-full" src="https://www.webrunners.de/wp-content/uploads/2015/06/schreenshot1.jpg" alt="schreenshot1" width="524" height="346" /></a></p>
<h3>Combining the search text with the tweet stream</h3>
<p>The function <code>allTweetsAbout</code> for searching the tweets is passed into the constructor of the view model. It takes a search text as an argument and returns an observable stream of tweets which is all we need to know. The internals of this function will not be discussed here because this article should focus on the consumption of observables as opposed to creation.</p>
<p>In order to combine the search text stream with the tweet stream we need to introduce the operators <code>Switch</code>, <code>Sample</code>, <code>Publish</code> / <code>Connect</code> and <code>ObserveOnDispatcher</code>. (The <code>Select</code> operator we have already seen in the <a href="https://www.webrunners.de/drawing-lines-with-rx/">previous part</a>.)</p>
<h4>Switch</h4>
<p>The combining operator <code>Switch</code> can be applied to an observable of nested observables. <code>Switch</code> only emits items from the most recent inner observable.</p>
<p>In our program we combine the observable of search texts with the tweet streams using the <code>Select</code> operator. The result is an observable of observable of tweets. As we are only interested in the most recent search this is a perfect application for <code>Switch</code>.</p>
<h4>Sample</h4>
<p>The filtering operator <code>Sample</code> emits only the most recent item for every specified periodic interval.</p>
<h4>Publish and Connect</h4>
<p>Publish allows us to share the actual values of an observable with multiple subscribers.</p>
<h4>ObserveOnDispatcher</h4>
<p>This extension method makes sure that the subscription is made on the UI thread. If we don&#8217;t use this in a WPF application it would cause some sort of threading exception.</p>
<p>Note that in order to be able to properly test the application we would use <code>ObserveOn</code> with an <code>IScheduler</code> instance instead which should be injected into our class from outside. More information on this can be found <a href="http://www.introtorx.com/content/v1.0.10621.0/16_TestingRx.html">here</a>.</p>
<h3>Composing the application</h3>
<p>We have introduced all the necessary Rx operators. But for updating the view model we need two more functions, <code>UpdateViewModelAwesomeTweets</code> and <code>UpdateViewModelBoringTweets</code> whose implementations are trivial. Now we have everything to compose the application as follows:</p>
<pre><code class="language-csharp">var searchTexts = this
    .ToObservable(() =&gt; SearchTextBox)
    .Throttle(TimeSpan.FromSeconds(2))
    .Where(x =&gt; x.Length &gt; 2);

var tweets = searchTexts
    .Select(allTweetsAbout)
    .Switch()
    .Sample(TimeSpan.FromSeconds(1))
    .Select(classifyTweet)
    .Publish();

tweets
    .Where(x =&gt; x.Score &gt; 1000)
    .Select(x =&gt; x.Tweet)
    .ObserveOnDispatcher()
    .Subscribe(UpdateViewModelAwesomeTweets);

tweets
    .Where(x =&gt; x.Score &lt;= 1000)
    .Select(x =&gt; x.Tweet)
    .ObserveOnDispatcher()
    .Subscribe(UpdateViewModelBoringTweets);

tweets.Connect();
</code></pre>
<p>The complete source code of this application can be downloaded <a href="https://github.com/webrunners/rx-examples/tree/master/Twitter">here</a>.</p>
<h2>Summary</h2>
<p><strong>Easy combination of multiple event streams</strong><br />Combining and handling multiple event streams is not a simple task. But with the help of Rx this becomes really easy.</p>
<p><strong>Dealing with time</strong><br />When the relationship with time is involved in the event processing Rx provides a set of powerful operators that deal with time like e.g. <code>Throttle</code> and <code>Sample</code>.</p>
<p><strong>Separation of concerns</strong><br />In the example application we have separated the concerns pretty well. We use small functions that all have a single responsibility like e.g. searching tweets, classifying tweets or updating the model. The integration of all these functions is expressed comprehensively by the composition with the Rx operators.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/webrunners/rx-examples/tree/master/Twitter">Source code</a></li>
<li><a href="http://reactivex.io/documentation/operators.html">ReactiveX &#8211; Operators</a></li>
<li><a href="https://www.youtube.com/watch?v=_VdIQTtRkb8">Video: An Event-driven and Reactive Future</a></li>
<li><a href="http://www.introtorx.com/content/v1.0.10621.0/16_TestingRx.html">Testing Rx</a></li>
<li><a href="http://blog.leifbattermann.de/2015/06/21/typesafe-conversion-of-viewmodel-property-to-observable-stream/">Typesafe conversion of viewmodel property to observable stream</a></li>
</ul>
<hr />
<p><small>The header image <a href="https://flic.kr/p/9eDKvi">&#8220;tweet&#8221;</a> by <a href="https://www.flickr.com/photos/mozzercork/">mozzercork</a> is licensed under a <a href="https://creativecommons.org/licenses/by/2.0/legalcode">Creative Commons Attribution 2.0</a>. The picture was modified to fit this article.</small></p>


<p></p>The post <a href="https://www.webrunners.de/en/twitter-with-rx/">Twitter with Rx</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Drawing lines with Rx</title>
		<link>https://www.webrunners.de/en/drawing-lines-with-rx/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=drawing-lines-with-rx</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Thu, 18 Jun 2015 15:09:16 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=99</guid>

					<description><![CDATA[<p>In part 1 and 2 of the series Reactive Extensions in theory and practice we covered some of the theory of Rx and introduced a nice visualization method with marble diagrams. In this post we will have a closer look at the operators Select, Zip and Skip and review a sample application where those operators [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/drawing-lines-with-rx/">Drawing lines with Rx</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>In part <a href="http://blog.webrunners.de/2015/06/03/short-introduction-to-reactive-extensions/">1</a> and <a href="http://blog.webrunners.de/2015/06/16/visualizing-sequences/">2</a> of the series <a href="https://www.webrunners.de/category/reactive-extensions/">Reactive Extensions in theory and practice</a> we covered some of the theory of Rx and introduced a nice visualization method with marble diagrams.</p>
<p>In this post we will have a closer look at the operators <code>Select</code>, <code>Zip</code> and <code>Skip</code> and review a sample application where those operators are extremely useful.</p>
<p>The application is a very simple WPF application where you can draw lines in a window. For each line the distance will be displayed. In fact the code for this program is so simple and declarative that it really shows the shining beauty and elegancy of Rx.</p>
<p><img decoding="async" title="UI" src="https://www.webrunners.de/wp-content/uploads/2015/06/skipzip_screenshot.jpg" alt="alt text" /></p>
<p><span id="more-9423"></span></p>
<p>The source code of the app can be downloaded <a href="https://github.com/webrunners/rx-examples/tree/master/SkipAndZip">here</a>.</p>
<h2>Operators</h2>
<p>Let&#8217;s first introduce the operators that are involved in this example.</p>
<h3>Select</h3>
<p><code>Select</code> is a transforming operator that projects the elements of an observable sequence into a new form by applying the function <code>f</code> to each element.</p>
<p><a href="http://blog.webrunners.de/wp-content/uploads/2015/06/select2.svg"><img decoding="async" class="alignnone size-full wp-image-190" src="http://blog.webrunners.de/wp-content/uploads/2015/06/select2.svg" alt="Marble diagram - Select" /></a></p>
<h3>Skip</h3>
<p><code>Skip</code> is a filtering operator that bypasses the first <code>n</code> elements of a sequence. The result is a sequence that emits all elements of the source sequence except the first <code>n</code> elements.</p>
<p><a href="http://blog.webrunners.de/wp-content/uploads/2015/06/skip.svg"><img decoding="async" class="alignnone size-full wp-image-191" src="http://blog.webrunners.de/wp-content/uploads/2015/06/skip.svg" alt="Marble diagram - Skip" /></a></p>
<h3>Zip</h3>
<p><code>Zip</code> is a combining operator that merges two sequences by applying a function <code>f</code> to each pair of elements. Pairs are created by combining each element of the first sequence with the element of the second sequence that has the same index as the first element.</p>
<p><a href="http://blog.webrunners.de/wp-content/uploads/2015/06/zip.svg"><img decoding="async" class="alignnone size-full wp-image-188" src="http://blog.webrunners.de/wp-content/uploads/2015/06/zip.svg" alt="Marble diagram - Zip" /></a></p>
<h2>Operators in practice</h2>
<p>To see the operators in action we will review <a href="https://github.com/webrunners/rx-examples/tree/master/SkipAndZip">this sample application</a> that lets us draw lines on the UI. For each line the length is displayed. The length is the distance between two positions on the UI represented by two <code>Point</code> instances. In this case the coordinates of the points are determined relatively to the canvas control of the main window.</p>
<p>Let&#8217;s go through the steps that are necessary to implement this.</p>
<p>First let&#8217;s take a look at the simple class <code>Line</code> which is the main type used in the application:</p>
<pre><code class="language-csharp">public class Line
{
    public Point PointA { get; private set; }
    public Point PointB { get; private set; }

    public double Length
    {
        get
        {
            var d = Point.Subtract(PointA, PointB);
            return Math.Sqrt(Math.Abs(d.X * d.X - d.Y * d.Y));
        }
    }

    private Line(Point a, Point b) { PointA = a; PointB = b; }

    public static Line Create(Point a, Point b)
    {
        return new Line(a, b);
    }
}
</code></pre>
<p>The implementation is straightforward. The factory method <code>Create</code> takes two points and returns a new <code>Line</code> instance. It is just for convenience because it simplifies the syntax when used instead of the constructor with Rx operators. <code>Length</code> calculates and returns the distance between the two points. For the sake of simplicity the value of <code>Length</code> is not stored locally which would be an optimization.</p>
<p>Now we have to convert the mouse button click events into an observable stream. This can be done with the <code>Observable.FromEventPattern&lt;TEventArgs&gt;</code> function. As the first parameter we have to provide the object instance that exposes the mouse click event which is the <code>MainWindow</code> instance itself. So we can pass in <code>this</code> here. The second parameter is the name of the event that we are interested in which is <code>"MouseUp"</code>. The result is an observable sequence of <code>EventPattern&lt;MouseButtonEventArgs&gt;</code>:</p>
<pre><code class="language-csharp">Observable.FromEventPattern&lt;MouseButtonEventArgs&gt;(this, "MouseUp")
</code></pre>
<p>Next we have to convert each <code>EventPattern</code> into a Position of type <code>Point</code>. We could do this by just using a lambda expression. But instead we define the little nested helper function <code>getPosition</code>. The benefit of the helper function is that it makes the code more compact later when the function is passed to the <code>Select</code> operator. The position is determined relatively to the <code>Canvas</code> UI control named <code>_box</code>.</p>
<pre><code class="language-csharp">Func&lt;EventPattern&lt;MouseButtonEventArgs&gt;, Point&gt; getPosition = 
    args =&gt; args.EventArgs.GetPosition(_box);
</code></pre>
<p>Finally we need a function that takes a line and updates the UI by drawing the line and displaying its length. Therefore we define a private method <code>UpdateUi</code>. The details here are WPF specific and not really relevant to us right now.</p>
<h3>Composing the operators</h3>
<p>Now we have defined all necessary functions. The only thing left to do is to transform and combine the observable sequence of click events by composing and applying the Rx operators <code>Select</code>, <code>Skip</code> and <code>Zip</code>.</p>
<blockquote><p>The idea is to create lines by taking each point of the sequence and combine it with its predecessor.</p></blockquote>
<p>The solution is simple and elegant. After we transformed the click stream to positions with <code>Select(getPosition)</code> we shift the sequence by one with <code>Skip(1)</code>. Then we merge the shifted sequence with the original sequence with <code>Zip</code> and pass in the factory method to create lines. That&#8217;s it!</p>
<p>There is no need to keep the state e.g. the last clicked position in a local or instance variable.</p>
<p>Here is marble diagram that visualizes how this works:</p>
<p><a href="http://blog.webrunners.de/wp-content/uploads/2015/06/draw_lines.svg"><img decoding="async" class="alignnone size-full wp-image-189" src="http://blog.webrunners.de/wp-content/uploads/2015/06/draw_lines.svg" alt="Marble diagram - Draw lines" /></a></p>
<h3>Connecting the observer</h3>
<p>Finally we have to connect the observer (which is the UI in this case) with the observable by calling the extension method <code>Subscribe</code> and pass in the <code>UpdateUi</code> function. Here is the code that is responsible for composing all the functions to create the program:</p>
<pre><code class="language-csharp">var points = Observable
    .FromEventPattern&lt;MouseButtonEventArgs&gt;(this, "MouseUp")
    .Select(getPosition);

points
    .Zip(points.Skip(1), Line.Create)
    .Subscribe(UpdateUi);
</code></pre>
<h2>Summary</h2>
<p>We have seen how a program can be composed by using observable sequences and applying Rx operators to them. The source code of this program is very concise and declarative. Also there is no state involved (except for the UI off course) that we have to be cautious of.</p>
<p>Using Reactive Extensions in event-based applications leads to code that is simple and elegant and therefore easy to understand, maintain and extend.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/webrunners/rx-examples/tree/master/SkipAndZip">Source code</a></li>
<li><a href="http://reactivex.io/documentation/operators.html">ReactiveX &#8211; Operators</a></li>
</ul>The post <a href="https://www.webrunners.de/en/drawing-lines-with-rx/">Drawing lines with Rx</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Visualizing sequences</title>
		<link>https://www.webrunners.de/en/visualizing-sequences/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=visualizing-sequences</link>
					<comments>https://www.webrunners.de/en/visualizing-sequences/#comments</comments>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Tue, 16 Jun 2015 09:19:23 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=80</guid>

					<description><![CDATA[<p>As we already know from part 1 an Observable is a sequence of ongoing events in time. These sequences and their compositions and transformations can be nicely visualized by marble diagrams in either textual or graphical representation. The visualization of Observables makes it very easy to understand what is going on even if you are [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/visualizing-sequences/">Visualizing sequences</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>As we already know from <a href="http://blog.webrunners.de/2015/06/03/short-introduction-to-reactive-extensions/">part 1</a> an Observable is a sequence of ongoing events in time. These sequences and their compositions and transformations can be nicely visualized by marble diagrams in either textual or graphical representation. The visualization of Observables makes it very easy to understand what is going on even if you are not an expert in Reactive Extensions.<br />
<span id="more-6775"></span></p>
<h2>Textual representation</h2>
<p>There is a simple textual representation that uses the following symbols:</p>
<table>
<thead>
<tr>
<th>Symbol</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>&#8211;&gt;</td>
<td>Timeline</td>
<td>flows from left to right</td>
</tr>
<tr>
<td>O</td>
<td>Item emitted by a sequence</td>
<td>when called <code>OnNext</code></td>
</tr>
<tr>
<td>X</td>
<td>Abnormal termination</td>
<td>when called <code>OnError</code></td>
</tr>
<tr>
<td>|</td>
<td>Successful completion</td>
<td>when called <code>OnCompleted</code></td>
</tr>
</tbody>
</table>
<p>A sequence with 3 items looks like this:</p>
<pre><code class="language-none">--O--O--O--|-&gt;
</code></pre>
<h3>Combining sequences</h3>
<p>The following diagram visualizes the <code>Select(f)</code> operator applied to <code>Seq1</code> that creates a result stream (<code>Result</code>) where each emitted value of <code>Seq1</code> is replaced according to the function <code>f</code>. In this case <code>f</code> adds one to the input value:</p>
<pre><code class="language-none">Seq1   --1---2-----3----&gt;
       Select(x =&gt; x + 1)
Result --2---3-----4----&gt;
</code></pre>
<h2>Graphical representation</h2>
<p>Here is the graphical representation of the example from above:</p>
<h2>Resources</h2>
<ul>
<li><a href="http://rxmarbles.com/">RxMarblesInteractive diagrams of Rx Observables</a></li>
<li><a href="http://reactivex.io/documentation/operators.html">ReactiveX &#8211; Operators</a></li>
</ul>The post <a href="https://www.webrunners.de/en/visualizing-sequences/">Visualizing sequences</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.webrunners.de/en/visualizing-sequences/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Short introduction to Reactive Extensions</title>
		<link>https://www.webrunners.de/en/short-introduction-to-reactive-extensions/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=short-introduction-to-reactive-extensions</link>
		
		<dc:creator><![CDATA[Finja Kolzem]]></dc:creator>
		<pubDate>Wed, 03 Jun 2015 08:55:51 +0000</pubDate>
				<category><![CDATA[Alle]]></category>
		<guid isPermaLink="false">http://blog.webrunners.de/?p=6</guid>

					<description><![CDATA[<p>The Reactive Extensions (Rx) is a library for programming with asynchronous data streams. It was originally developed at Microsoft for the .NET Framework but is now available as a seperate library. Meanwhile it has been ported to many other languages and platforms as e.g. Java, Scala, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others. Rx [&#8230;]</p>
The post <a href="https://www.webrunners.de/en/short-introduction-to-reactive-extensions/">Short introduction to Reactive Extensions</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></description>
										<content:encoded><![CDATA[<p>The <a title="" href="http://reactivex.io/">Reactive Extensions (Rx)</a> is a library for programming with asynchronous data streams. It was originally developed at Microsoft for the .NET Framework but is now available as a seperate library. Meanwhile it has been ported to many other languages and platforms as e.g. Java, Scala, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others.</p>
<p>Rx can be used in desktop as well as web-based applications on either server or client side. A few common situations / problems where you might benefit from using Rx are:</p>
<ul>
<li>Unresponsive UI</li>
<li>Long running computations that could potentially block other threads</li>
<li>Asynchronous programming where multiple sources of data and events have to be combined</li>
<li>Enabling and managing concurrency on backend independent of the consumers implementation</li>
<li>Handling errors and cancellation of asynchronous tasks</li>
</ul>
<p>In this post I will introduce some general ideas behind Rx and show how it can help in some of the situations stated above. If you are new to Rx it will give you a basic understanding of what Rx is and where it can be useful to apply.<br />
<span id="more-6"></span></p>
<p>The examples are all presented in C#. But the concepts apply to all programming languages.</p>
<h2>Definition</h2>
<p>A definition of Rx could be:</p>
<blockquote><p>Rx is a library for programming with asynchronous data streams. It is a combination of the <a title="" href="http://en.wikipedia.org/wiki/Observer_pattern">observer</a> and the <a title="" href="http://en.wikipedia.org/wiki/Iterator_pattern">iterator pattern</a> as described by the <a href="http://en.wikipedia.org/wiki/Design_Patterns">Gang of Four</a> combined with ideas and concepts from functional programming.</p></blockquote>
<h2>Querying Data</h2>
<p>To get an idea when it is useful to use Rx let us look at ways how to retrieve data. Basically a query result can be either a single object or a collection of objects. The data can be queried either synchronous or asynchronous. This produces the following matrix:</p>
<table>
<thead>
<tr>
<th></th>
<th>Single</th>
<th>Multiple</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sync</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Async</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h3>Sync Single</h3>
<p>A function that returns a single object and is executed synchronously is probably one of the most common scenarios that we encounter. In the example the function is called <code>GetData()</code> and the return value is of the generic type <code>T</code> as shown in the following table.</p>
<table>
<thead>
<tr>
<th></th>
<th>Single</th>
<th>Multiple</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sync</td>
<td><strong><code>T GetData()</code></strong></td>
<td></td>
</tr>
<tr>
<td>Async</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>Calling the method and processing the result might look something like this:</p>
<pre><code class="language-csharp">string s = GetData();

if(s.Equals(x))
    // do something
else
    // do something else
</code></pre>
<p>If this code was implemented behind a user interface the process will be blocked for however long it will take to retrieve the value because this is done synchronously.</p>
<h3>Sync Multiple</h3>
<p>When we examine the synchronous query of multiple values we will see the same behaviour except that the return value is a collection of objects of type <code>T</code>.</p>
<table>
<thead>
<tr>
<th></th>
<th>Single</th>
<th>Multiple</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sync</td>
<td><code>T GetData()</code></td>
<td><strong><code>IEnumerable&lt;T&gt; GetData()</code></strong></td>
</tr>
<tr>
<td>Async</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>The <a href="http://en.wikipedia.org/wiki/Language_Integrated_Query">LINQ</a> library provides a rich toolbox of query operators to create, transform, combine and filter collections. In the example however we want to iterate over all the values and do some processing with each of them.</p>
<pre><code class="language-csharp">IEnumerable&lt;string&gt; values = GetData();

foreach(string value in values)
{
    if(value.Equals(x))
        // do something
    else
        // do something else
}
</code></pre>
<p>Again this is done synchronously and the UI will be blocked.</p>
<h3>Async Single</h3>
<p>To make the UI more responsive values can be queried asynchronously. In case of a single value the function might return a <code>Task&lt;T&gt;</code>. A <code>Task</code> in C# can be seen as the equivalent of the <code>Future</code> in Java. It is the result of an asynchronous computation.</p>
<table>
<thead>
<tr>
<th></th>
<th>Single</th>
<th>Multiple</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sync</td>
<td><code>T GetData()</code></td>
<td><code>IEnumerable&lt;T&gt; GetData()</code></td>
</tr>
<tr>
<td>Async</td>
<td><strong><code>Task&lt;T&gt; GetData()</code></strong></td>
<td></td>
</tr>
</tbody>
</table>
<p>Processing the result of a Task can be done synchronously which again will block.</p>
<pre><code class="language-csharp">Task&lt;T&gt; task = GetData();

if (task.Result.Equals(x))
    // do something
else
    // do something else
</code></pre>
<p>So that is not really an improvement. A better workflow when creating a responsive UI would be:</p>
<ul>
<li>Respond to some user action</li>
<li>Do work on a background thread</li>
<li>Pass the result back to the UI thread</li>
<li>Update the UI</li>
</ul>
<p>To achieve this we should consider the async features in .NET 4.5 or apply a callback. A callback is a function that is passed as an argument and will be called at a later time e.g. with the result of a long running computation. In this case we can use the <code>ContinueWith</code> method of <code>Task</code> that takes a function that is executed asynchronously.</p>
<pre><code class="language-csharp">task.ContinueWith(t =&gt;
{
    if (t.Result.Equals(x))
        // do something
    else
        // do something else
});
</code></pre>
<h3>Async Multiple</h3>
<p>Asynchronous computations that yield collections of values can also be handled with callbacks. Actually this is what is done in many cases. But we might quite easily run into several problems as the application becomes more and more complex.</p>
<p>E.g. there is no way to start iterating over the result and process the values before the whole computation completes. If loading the whole collection takes a long time it would be very convenient to start working with the first part of the list while the rest is still processing. But when using callbacks this is not possible.</p>
<p>And what if we want to process each element again asynchronously and then each result of that yet again&#8230; and so on? The consequence would be a deeply nested composition of callbacks which will become very unwieldy and won&#8217;t be easily maintainable any more.</p>
<blockquote><p>With nested composition callbacks become unwieldy and lead to the need to synchronize.</p></blockquote>
<p>This is where Rx comes into play with the main type <code>IObservable&lt;T&gt;</code> &#8211; the counter part of <code>IEnumerable&lt;T&gt;</code>.</p>
<table>
<thead>
<tr>
<th></th>
<th>Single</th>
<th>Multiple</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sync</td>
<td><code>T GetData()</code></td>
<td><code>IEnumerable&lt;T&gt; GetData()</code></td>
</tr>
<tr>
<td>Async</td>
<td><code>Task&lt;T&gt; GetData()</code></td>
<td><strong><code>IObservable&lt;T&gt; GetData()</code></strong></td>
</tr>
</tbody>
</table>
<p><code>IObservable&lt;T&gt;</code> represents an asynchronous data stream of objects of type <code>T</code>. Consuming the result is quite simple:</p>
<pre><code class="language-csharp">IObservable&lt;T&gt; o = GetData();

o.Subscribe(t =&gt;
{
    if (t.Equals(x))
        // do something
    else
        // do something else
});
</code></pre>
<p>The <code>Subscribe</code> method has several overloads. In the example above it takes an action as a single argument which will be applied to each value from the Observable.</p>
<h1>Composable functions</h1>
<p>As well as LINQ Rx also includes a rich library of higher-order functions that allow us to transform, combine, filter etc. observable sequences. Those functions are easily composable. This is one of the really great benefits of Rx because it makes querying, combining and transforming asynchronous data streams as simple as applying LINQ queries.</p>
<p>Roughly the set of functions can be divided into the following categories:</p>
<p><strong>Transform:</strong> Select, SelectMany, Aggregate &#8230;</p>
<p><strong>Filter:</strong> Skip, Take, TakeWhile, Where &#8230;</p>
<p><strong>Combine:</strong> Concat, Merge, Zip &#8230;</p>
<p><strong>Boolean Operators</strong>: Any, All, Contains &#8230;</p>
<p><strong>Mathematical Operators:</strong> Max, Min, Average, Count, Sum &#8230;</p>
<p><strong>Concurrency:</strong> ObserveOn, SubscribeOn &#8230;</p>
<p><strong>Error Handling:</strong> OnErrorReturn, OnErrorResume &#8230;</p>
<p>Here is a simple example of how some of these functions can be combined:</p>
<pre><code class="language-csharp">IObservable&lt;int&gt; observable = GetData();

observable
    .Skip(1)
    .Take(3)
    .Where(x =&gt; x &lt; 10)
    .Select(x =&gt; x + 1)
    .Subscribe(Console.WriteLine);
</code></pre>
<h2>IEnumerable vs. IObservable</h2>
<p>To get an even better understanding of what an <code>IObservable&lt;T&gt;</code> is we will compare it to the <code>IEnumerable&lt;T&gt;</code>.</p>
<h3>IEnumerable</h3>
<p>The method <code>IEnumerable.GetEnumerator()</code> returns an object of type <code>IEnumerator</code> which iterates over collections and has the following methods:</p>
<ul>
<li><code>bool MoveNext()</code> &#8211; Advances the enumerator to the next element of the collection. Returns true if it succeeds and false if it fails (when the enumerator points to the last element of the collection or empty list).</li>
<li><code>T Current{ get; }</code> &#8211; Returns the current element in the list.</li>
<li><code>throws Exception</code> &#8211; This is actually not a method of the interface. But an exception might be thrown when calling <code>Current</code> so an exception is a potential implicit return value of <code>Current</code>. In other words the return value of <code>Current</code> could be described as <code>Either&lt;T, Exception&gt;</code> or <code>Tuple&lt;T, Exception&gt;</code> or similar types.</li>
<li><code>void Dispose()</code> &#8211; Disposes of all resources used by the enumerator.</li>
</ul>
<blockquote><p>The general task of an enumerator is to <em>pull</em> data from a collection.</p></blockquote>
<p>Below we can see the enumerator in action (Note that this is just for demonstration and is not good code. Usually we would use a <code>foreach</code> statement to do the iteration over a collection.):</p>
<pre><code class="language-csharp">var enumerator = new List&lt;int&gt; { 1, 2, 3 }.GetEnumerator();

while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}
enumerator.Dispose();
</code></pre>
<h3>IObservable</h3>
<p>Each method of the <code>IEnumerator</code> interface has its corresponding method in the <code>IObserver</code> interface:</p>
<ul>
<li><code>OnCompleted()</code> &#8211; Notifies the observer that the provider has finished sending data.</li>
<li><code>OnNext(T)</code> &#8211; Pushes the next value to the observer.</li>
<li><code>OnError(Exception)</code> &#8211; Notifies the observer that an error occurred.</li>
</ul>
<blockquote><p>The general task of an observer is to <em>push</em> data into a stream.</p></blockquote>
<p>Here is an example of how the methods described above can be called in order to create an observable sequence:</p>
<pre><code class="language-csharp">public static IObservable&lt;int&gt; GetData()
{
    return Observable.Create&lt;int&gt;(o =&gt;
    {
        o.OnNext(1);
        o.OnNext(2);
        o.OnNext(3);
        o.OnCompleted();

        return Disposable.Empty;
    });
}
</code></pre>
<p>For detailed information on how this works and on all the query operators and more check out the amazing online resource about <a title="" href="http://www.introtorx.com/">Rx .NET</a> by Lee Campbell.</p>
<p>The methods of <code>IEnumerator</code> and <code>IObservable</code> relate to each other in a special way as shown in the following diagram. Actually they are <a title="" href="http://csl.stanford.edu/~christos/pldi2010.fit/meijer.duality.pdf">dual</a> to each other.</p>
<table>
<thead>
<tr>
<th align="right">IEnumerable</th>
<th align="left">IObservable</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right"><em>pull</em></td>
<td align="left"><em>push</em></td>
</tr>
<tr>
<td align="right"><code>bool MoveNext()</code></td>
<td align="left"><code>void OnCompleted()</code></td>
</tr>
<tr>
<td align="right"><code>T Current { get; }</code></td>
<td align="left"><code>void OnNext()</code></td>
</tr>
<tr>
<td align="right"><code>throws Exception</code></td>
<td align="left"><code>void OnError(Exception)</code></td>
</tr>
</tbody>
</table>
<p>On an observable sequence and on an enumerable sequence the same or at least very similar functions can be applied:</p>
<pre><code class="language-csharp">// IObservable&lt;string&gt;
// that emits 75 Strings
GetData()
    .Skip(10)
    .Take(5)
    .Select(x =&gt; x + "_transformed")
    .Subscribe(x =&gt; Console.WriteLine("next =&gt; " + x));

// IEnumerablee&lt;string&gt;
// that contains 75 Strings
GetData()
    .Skip(10)
    .Take(5)
    .Select(x =&gt; x + "_transformed").ToList()
    .ForEach(x =&gt; Console.WriteLine("next =&gt; " + x));
</code></pre>
<h2>Summary</h2>
<p>We have seen how Rx can help to make the UI responsive when dealing with computationally expensive tasks.</p>
<p>Also we could get an idea of how easy and comfortable it is to handle asynchronous data from multiple sources with the use of the LINQ-style query operators.</p>
<p>Enabling and managing concurrency on the backend as well as handling exceptions, cancellation etc. are other areas where Rx really shines. But these details go beyond the scope of this post. For more information on that please check out the resources below.</p>
<p>Things to keep in mind:</p>
<ul>
<li>Rx is a library for programming with asynchronous data streams</li>
<li>Rx provides a rich library of composable functions to transform, combine, filter etc.</li>
<li>The key types are <code>IObserver&lt;T&gt;</code> and <code>IObservable&lt;T&gt;</code></li>
<li>The pair of types <code>IObservable&lt;T&gt;</code> and <code>IObserver&lt;T&gt;</code> is dual to the pair <code>IEnumerable&lt;T&gt;</code> and <code>IEnumerator&lt;T&gt;</code></li>
<li>Rx provides rich functionalities for a scenario where a producer asynchronously pushes data to a consumer</li>
</ul>
<h2>Resources</h2>
<ul>
<li><a href="http://reactivex.io/">ReactiveX</a></li>
<li><a href="http://www.introtorx.com/">Getting started with the Reactive Extensions to .NET</a></li>
<li><a href="https://github.com/ReactiveX/RxJava">Java</a></li>
<li><a href="https://github.com/Reactive-Extensions/RxJS">JavaScript</a></li>
<li><a href="https://github.com/Reactive-Extensions/Rx.NET">C#</a></li>
<li><a href="https://github.com/ReactiveX/RxScala">Scala</a></li>
<li><a href="https://github.com/ReactiveX/RxClojure">Clojure</a></li>
<li><a href="https://github.com/Reactive-Extensions/RxCpp">C++</a></li>
<li><a href="https://github.com/Reactive-Extensions/Rx.rb">Ruby</a></li>
<li><a href="https://github.com/ReactiveX/RxPY">Python</a></li>
<li><a href="https://github.com/ReactiveX/RxGroovy">Groovy</a></li>
</ul>
<hr />
<p><small>The header image <a href="https://flic.kr/p/9ahgHp">&#8220;Long exposure head lamps &amp; tail lights&#8221;</a> by <a href="https://www.flickr.com/photos/williamphotography/">JC+A</a> is licensed under a <a href="https://creativecommons.org/licenses/by/2.0/legalcode">Creative Commons Attribution 2.0</a>. The picture was modified to fit this article.</small></p>The post <a href="https://www.webrunners.de/en/short-introduction-to-reactive-extensions/">Short introduction to Reactive Extensions</a> first appeared on <a href="https://www.webrunners.de">Webrunners</a>.]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
