<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Words and Thoughts</title>
    <subtitle></subtitle>
    <link href="https://ysegorov.github.io/" rel="alternative" />
    <link href="https://ysegorov.github.io/atom.xml" rel="self" />
    <id>https://ysegorov.github.io</id>
    <updated>2026-07-26T16:09:29.438531+00:00</updated>
    
    
    
    
    
    <entry>
        <title>Initial commit</title>
        <link href="https://ysegorov.github.io/2015/initial-commit/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/initial-commit/</id>
        <updated>2026-07-26T12:40:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;initial-commit&#34;&gt;Initial commit &lt;a class=&#34;header-anchor&#34; href=&#34;#initial-commit&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;strong&gt;Update 1.&lt;/strong&gt; This blog is powered by self-made library &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt;&lt;/s&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;strong&gt;Update 2.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library has been moved to archive, no plans to develop it further&lt;/s&gt;.
&lt;s&gt;I&#39;ve switched to &lt;a href=&#34;https://www.getzola.org&#34;&gt;zola&lt;/a&gt; to manage the blog&lt;/s&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 3.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library was unarchived, rebuilt from scratch and released as 3.0.0 version.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is just a very first record in the blog which will be powered by
&lt;s&gt;&lt;a href=&#34;http://blog.getpelican.com/&#34;&gt;Pelican&lt;/a&gt;&lt;/s&gt;.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Module level abstraction in python</title>
        <link href="https://ysegorov.github.io/2015/module-level-abstraction-in-python/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/module-level-abstraction-in-python/</id>
        <updated>2015-01-30T17:40:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;module-level-abstraction-in-python&#34;&gt;Module-level abstraction in Python &lt;a class=&#34;header-anchor&#34; href=&#34;#module-level-abstraction-in-python&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Sample code first.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-
#
# file: jukoro/pickle.py

import cPickle


load = cPickle.load
loads = cPickle.loads


def dump(obj, f):
    return cPickle.dump(obj, f, protocol=cPickle.HIGHEST_PROTOCOL)


def dumps(obj):
    return cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No magic inside - in our own project we&#39;ve created &lt;strong&gt;&lt;a href=&#34;http://pickle.py&#34;&gt;pickle.py&lt;/a&gt;&lt;/strong&gt; module,
the one to be used in place of &lt;strong&gt;cPickle&lt;/strong&gt; from standart library.&lt;/p&gt;
&lt;p&gt;As a result we&#39;ve got an &lt;a href=&#34;http://en.wikipedia.org/wiki/Abstraction_principle_(computer_programming)&#34;&gt;abstraction&lt;/a&gt;, which helps us to keep code DRY and
improves code manageability.&lt;/p&gt;
&lt;p&gt;I like this approach.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Grief</title>
        <link href="https://ysegorov.github.io/2015/grief/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/grief/</id>
        <updated>2015-03-01T06:15:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;grief&#34;&gt;Grief &lt;a class=&#34;header-anchor&#34; href=&#34;#grief&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Boris Nemtsov.&lt;/p&gt;
&lt;p&gt;Terrible pain. Emptiness inside. Impossible to comprehend.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Chtd</title>
        <link href="https://ysegorov.github.io/2015/chtd/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/chtd/</id>
        <updated>2015-03-28T04:25:00+00:00</updated>
        <summary>Working for Chtd</summary>
        <content type="html">
            &lt;h1 id=&#34;chtd&#34;&gt;Chtd &lt;a class=&#34;header-anchor&#34; href=&#34;#chtd&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&#34;preface&#34;&gt;Preface &lt;a class=&#34;header-anchor&#34; href=&#34;#preface&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ve started to work for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; in October 2011 and worked till
February 2015.
It was a good time and I want to say thank you to everyone who worked with.&lt;/p&gt;
&lt;p&gt;At the moment of writing this post the company is in a difficult sutiation
and it had to shrink (four of the six developers were forced
to leave the company).&lt;/p&gt;
&lt;p&gt;This is going to be a long post and probably I&#39;ll keep it as is.&lt;/p&gt;
&lt;h2 id=&#34;context&#34;&gt;Context &lt;a class=&#34;header-anchor&#34; href=&#34;#context&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m going to sum up my experience working as a developer for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt;
talking about the some interesting points.&lt;/p&gt;
&lt;p&gt;The company has developed its own implementation of graph-oriented database
(think of &lt;a href=&#34;http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model&#34;&gt;EAV&lt;/a&gt;) built on top of &lt;strong&gt;PostgreSQL&lt;/strong&gt; using &lt;strong&gt;Django&lt;/strong&gt;
called &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt;
(authors of the core are &lt;em&gt;Vjacheslav Fyodorov&lt;/em&gt; and &lt;em&gt;Konstantin Lopuhin&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The database provides a way of storing historical data meaning we have a full
history of changes in it (no physical delete operations). The library for this
is open sourced and is called &lt;a href=&#34;https://bitbucket.org/chtd/documents&#34;&gt;documents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A typical project on the basis of &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt; consists of several libraries
providing needed functionality.&lt;/p&gt;
&lt;p&gt;Working with &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt; means we can build reports almost unlimited
in size and have automatic calculations according to calc rules
specified by analysts.&lt;/p&gt;
&lt;p&gt;We have a specialized report builder and some other useful tools.&lt;/p&gt;
&lt;h2 id=&#34;workflow&#34;&gt;Workflow &lt;a class=&#34;header-anchor&#34; href=&#34;#workflow&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is rather important point to begin with it. Going back to 2011
the company used
selfhosted &lt;strong&gt;subversion&lt;/strong&gt; as a version control system and actually there was no
established workflow for development. The team was small and for some time the
situation was acceptable. But the more we wrote the code more difficult it
becomes to control the situation.&lt;/p&gt;
&lt;p&gt;I don&#39;t remember exact dates but we changed it.&lt;/p&gt;
&lt;p&gt;As a first step it was switch to &lt;strong&gt;mercurial&lt;/strong&gt; repositories hosted by
&lt;a href=&#34;https://bitbucket.org&#34;&gt;BitBucket&lt;/a&gt;. We&#39;ve splitted monolitic &lt;strong&gt;svn&lt;/strong&gt;-repository to several
&lt;strong&gt;hg&lt;/strong&gt; repos.&lt;/p&gt;
&lt;p&gt;As a second step we&#39;ve adopted &lt;a href=&#34;http://nvie.com/posts/a-successful-git-branching-model/&#34;&gt;gitflow&lt;/a&gt; as a main workflow to work with
features, fixes and releases (it was my investigation about possible
workflows which led us to this excellent solution). Thank you, &lt;em&gt;Vincent
Driessen&lt;/em&gt;, for sharing your experience!&lt;/p&gt;
&lt;p&gt;As a third step we&#39;ve started to use pull requests to review the code to be
merged to &lt;em&gt;default&lt;/em&gt; branches.&lt;/p&gt;
&lt;p&gt;From the very beginning we were using &lt;strong&gt;Redmine&lt;/strong&gt; to track issues and manage
projects and it&#39;s just great.&lt;/p&gt;
&lt;h2 id=&#34;automation&#34;&gt;Automation &lt;a class=&#34;header-anchor&#34; href=&#34;#automation&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&#34;bitbucket-and-redmine&#34;&gt;BitBucket and Redmine &lt;a class=&#34;header-anchor&#34; href=&#34;#bitbucket-and-redmine&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using &lt;strong&gt;svn&lt;/strong&gt; we had a post-commit hook configured to send email with diff to
developers mailing list.&lt;/p&gt;
&lt;p&gt;After switching to &lt;a href=&#34;https://bitbucket.org&#34;&gt;BitBucket&lt;/a&gt; we wanted to keep these emails
with diff so our internal project called &lt;strong&gt;bbhook&lt;/strong&gt; was born and released by me.&lt;/p&gt;
&lt;p&gt;It is backed by &lt;strong&gt;PostgreSQL&lt;/strong&gt; and &lt;strong&gt;Django&lt;/strong&gt; and has two modes of operation -
as a service to be notified by &lt;a href=&#34;https://bitbucket.org&#34;&gt;BitBucket&lt;/a&gt; about push and
as a django-command configured to run by crontab every 5 minutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bbhook&lt;/strong&gt; project can handle multiple &lt;strong&gt;hg&lt;/strong&gt; repositories and under the hood
it does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;update repositories mirrors (repositories must be cloned on the same
server running &lt;strong&gt;bbhook&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;process each new commit arrived from &lt;a href=&#34;https://bitbucket.org&#34;&gt;BitBucket&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;get diff&lt;/li&gt;
&lt;li&gt;prepare email text using &lt;strong&gt;pygments&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;send email&lt;/li&gt;
&lt;li&gt;parse commit message to get &lt;strong&gt;Redmine&lt;/strong&gt; issue number&lt;/li&gt;
&lt;li&gt;post a message to corresponding &lt;strong&gt;Redmine&lt;/strong&gt; issue&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bbhook&lt;/strong&gt; works pretty well and we had just a few issues with it.&lt;/p&gt;
&lt;h3 id=&#34;fabric&#34;&gt;Fabric &lt;a class=&#34;header-anchor&#34; href=&#34;#fabric&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Going back to 2011 and 2012 we were using makefile to prepare configuration files
to deploy a web service (project built on &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It was a working solution but I wasn&#39;t satisfied with it. We still had
a lot of things to do by hand.&lt;/p&gt;
&lt;p&gt;It should be noted that we had one development server running a lot of web
services to be tested and reviewed by our testers and analysts. The time was
critical here - we were spending too much time deploying a service.&lt;/p&gt;
&lt;p&gt;So, I&#39;ve remembered of &lt;a href=&#34;http://www.fabfile.org/&#34;&gt;Fabric&lt;/a&gt; and some time later we were using
our specific &lt;strong&gt;fabfile&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Its initial version had several most important commands for us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deploy a new service from a specified &lt;strong&gt;hg&lt;/strong&gt; project branch&lt;/li&gt;
&lt;li&gt;update previously deployed service&lt;/li&gt;
&lt;li&gt;create &lt;strong&gt;postgresql&lt;/strong&gt; database according to settings&lt;/li&gt;
&lt;li&gt;load &lt;strong&gt;postgresql&lt;/strong&gt; dump to database or&lt;/li&gt;
&lt;li&gt;load database with initial data&lt;/li&gt;
&lt;li&gt;and some others&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later the &lt;strong&gt;fabfile&lt;/strong&gt; was extended to build a project distribution, to attach
newly deployed service to &lt;strong&gt;apache&lt;/strong&gt; instance, to clean up service etc.&lt;/p&gt;
&lt;p&gt;The core command was &lt;strong&gt;deploy&lt;/strong&gt; and combined with others we could deploy a
service by issuing just one command in &lt;strong&gt;bash&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The key win here was a way we specify service settings (server name, db
parameters etc.) - in a command line instead of manually editing configuration
file.&lt;/p&gt;
&lt;h3 id=&#34;static-files&#34;&gt;Static files &lt;a class=&#34;header-anchor&#34; href=&#34;#static-files&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;. Sometimes I&#39;m still fighting with &lt;strong&gt;gulp&lt;/strong&gt; spending too much time
configuring it. The &lt;a href=&#34;http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/&#34;&gt;article by Keith Cirkel&lt;/a&gt;
helped a lot to start using &lt;code&gt;npm&lt;/code&gt; as a build tool.&lt;/p&gt;
&lt;p&gt;This is a very long story on its own that is why I&#39;ll not go into details.&lt;/p&gt;
&lt;p&gt;We had a &lt;a href=&#34;https://djangoproject.com/&#34;&gt;Django&lt;/a&gt;-based project with a lot of libraries.
Some of them had static files - &lt;strong&gt;javascript&lt;/strong&gt;, &lt;strong&gt;css&lt;/strong&gt;, &lt;strong&gt;handlebars&lt;/strong&gt;
templates for client-side, &lt;strong&gt;less&lt;/strong&gt; and &lt;strong&gt;sass&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We passed this way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;webassets&lt;/strong&gt; library (&lt;strong&gt;python&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;grunt&lt;/strong&gt; (&lt;strong&gt;nodejs&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gulp&lt;/strong&gt; (&lt;strong&gt;nodejs&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;selfmade &lt;strong&gt;bundler&lt;/strong&gt; (&lt;strong&gt;nodejs&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was managing switch to &lt;strong&gt;grunt&lt;/strong&gt; and to &lt;strong&gt;gulp&lt;/strong&gt; and I am the only author of
&lt;strong&gt;bundler&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Reasons for this journey were speed and stability. We need speed to compile
static files and we need stability deploying new services on different servers
running different Linux flavours.&lt;/p&gt;
&lt;p&gt;Using &lt;strong&gt;grunt&lt;/strong&gt; we were suffering from speed and using &lt;strong&gt;gulp&lt;/strong&gt; we were
suffering from stability (stability of &lt;strong&gt;gulp plugins&lt;/strong&gt; to be installed on
different servers).&lt;/p&gt;
&lt;p&gt;I am sure these are not the issues any more for &lt;strong&gt;grunt&lt;/strong&gt; and &lt;strong&gt;gulp&lt;/strong&gt; (and I
am successfully using &lt;strong&gt;gulp&lt;/strong&gt; in my pet projects) but at some moment I&#39;ve
decided to drop this dependency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bundler&lt;/strong&gt; is a one &lt;strong&gt;javascript&lt;/strong&gt; file (&lt;strong&gt;nodejs&lt;/strong&gt; module) which is rather
complex inside but works pretty well.&lt;/p&gt;
&lt;p&gt;There is a chance I&#39;ll write a post focusing on &lt;strong&gt;bundler&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s all for automation section.&lt;/p&gt;
&lt;h2 id=&#34;python-javascript&#34;&gt;Python, Javascript &lt;a class=&#34;header-anchor&#34; href=&#34;#python-javascript&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This can be a huge section but I&#39;ll focus only on some examples (without any
specific order).&lt;/p&gt;
&lt;h3 id=&#34;low-level-netdb-administration&#34;&gt;Low-level NetDB administration &lt;a class=&#34;header-anchor&#34; href=&#34;#low-level-netdb-administration&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was my first library written for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; and we called it
&lt;em&gt;Object editor&lt;/em&gt; (&lt;em&gt;oditor&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Due to &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt; specific internals there was a need for an
administration tool (&lt;a href=&#34;https://djangoproject.com/&#34;&gt;Django&lt;/a&gt; embedded admin site didn&#39;t suit us).&lt;/p&gt;
&lt;p&gt;I think it was great for me to create &lt;em&gt;oditor&lt;/em&gt; because I had a way to better
understand &lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt; internals.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Oditor&lt;/em&gt; had two implementations.&lt;/p&gt;
&lt;p&gt;The first one was made using simple a-la &lt;strong&gt;REST&lt;/strong&gt; backend and
&lt;a href=&#34;http://dojotoolkit.org/&#34;&gt;Dojo&lt;/a&gt;-based frontend.&lt;/p&gt;
&lt;p&gt;To tell you the truth - I don&#39;t like &lt;a href=&#34;http://dojotoolkit.org/&#34;&gt;Dojo&lt;/a&gt;.
It is great and awesome but it&#39;s not for me.
I am sure there is something with me, not with &lt;a href=&#34;http://dojotoolkit.org/&#34;&gt;Dojo&lt;/a&gt;. I&#39;ll keep it as is.&lt;/p&gt;
&lt;p&gt;The second implementation was made using &lt;strong&gt;Backbone&lt;/strong&gt; and &lt;strong&gt;Bootstrap&lt;/strong&gt;
(details on them follow) and it was a big step forward to better &lt;strong&gt;python&lt;/strong&gt; and
&lt;strong&gt;javascript&lt;/strong&gt; code and to usability.&lt;/p&gt;
&lt;h3 id=&#34;backbone-and-bootstrap&#34;&gt;Backbone and Bootstrap &lt;a class=&#34;header-anchor&#34; href=&#34;#backbone-and-bootstrap&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Going back to 2011/2012 my javascript code was ugly.
I was the beginner and I was trying to have code organized but I&#39;m not sure
I&#39;ve managed it.&lt;/p&gt;
&lt;p&gt;As it usually happens there is a moment at which you understand - you have to
do something.
And by chance there was a project in which I was the only person responsible
for frontend.&lt;/p&gt;
&lt;p&gt;I took the chance and created the basis for some of our client-side libraries.&lt;/p&gt;
&lt;p&gt;It was based on modification of &lt;a href=&#34;https://github.com/af/djangbone&#34;&gt;djangbone&lt;/a&gt; for backend
(an excellent library I must say).&lt;/p&gt;
&lt;p&gt;And it is based on &lt;a href=&#34;http://backbonejs.org/&#34;&gt;backbone&lt;/a&gt;, &lt;a href=&#34;http://marionettejs.com/&#34;&gt;marionette&lt;/a&gt; and
&lt;a href=&#34;http://getbootstrap.com/2.3.2/&#34;&gt;bootstrap&lt;/a&gt; - for frontend.&lt;/p&gt;
&lt;p&gt;I think it was one of the most important steps during the history of
&lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; because &lt;a href=&#34;https://qubequ.com&#34;&gt;QuBeQu&lt;/a&gt; (&lt;a href=&#34;http://chtd.ru/netdb&#34;&gt;NetDB&lt;/a&gt; SaaS solution)
was built on top of this library.&lt;/p&gt;
&lt;h3 id=&#34;user-permissions&#34;&gt;User permissions &lt;a class=&#34;header-anchor&#34; href=&#34;#user-permissions&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is a story about refactoring &lt;strong&gt;python&lt;/strong&gt; code.&lt;/p&gt;
&lt;p&gt;We had rather complicated permissions system developed back to 2012. Really
complicated. The author of the system has left the company a year later.&lt;/p&gt;
&lt;p&gt;Supporting one of our projects we&#39;ve got a complain from the end user about
speed. It took too much time loading one specific page from our web service
(more than a minute - awful).&lt;/p&gt;
&lt;p&gt;Profiling showed that it&#39;s user permissions system to blame.&lt;/p&gt;
&lt;p&gt;Quick tests showed a possible way of fixing it and at first I was thinking it
will took from seven to ten days.
Actually it took almost two months if I&#39;m not mistaken.&lt;/p&gt;
&lt;p&gt;I should say there was my bad refactoring tests and I lost a week or so but
still - there is a huge codebase and my estimates were naive.&lt;/p&gt;
&lt;p&gt;Refactoring the code was a great lesson.&lt;/p&gt;
&lt;p&gt;For the first time I&#39;ve tried to use Python descriptors and I really liked it.&lt;/p&gt;
&lt;p&gt;Python descriptors are a great way of structuring your codebase.&lt;/p&gt;
&lt;p&gt;The result of the refactoring was awesome - page load time decreased to 1
second (from more than a minute!).&lt;/p&gt;
&lt;h3 id=&#34;digital-signature&#34;&gt;Digital signature &lt;a class=&#34;header-anchor&#34; href=&#34;#digital-signature&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We had a couple of projects with the need for digital signature support.&lt;/p&gt;
&lt;p&gt;In general this is about integration with &lt;a href=&#34;http://cryptopro.ru/&#34;&gt;CryptoPro&lt;/a&gt; software
(Russia-only solution).&lt;/p&gt;
&lt;p&gt;One of the tasks here was to provide full functionality for users having
certificates signed by accredited certified centers.&lt;/p&gt;
&lt;p&gt;There is a specialized portal distributing the XML list of accredited centers
but that is not enough. We need to load CRLs too and there is no single point
to get all CRLs from.&lt;/p&gt;
&lt;p&gt;It took some time to develop an optimal solution (this is about fetching data
from Internet).&lt;/p&gt;
&lt;p&gt;It was one more battle for speed to load certificates and CRLs within
a reasonable time.&lt;/p&gt;
&lt;h3 id=&#34;olap&#34;&gt;OLAP &lt;a class=&#34;header-anchor&#34; href=&#34;#olap&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mostly client-side library acting as an OLAP builder built on top of our
&lt;a href=&#34;http://backbonejs.org/&#34;&gt;backbone&lt;/a&gt;-based library.&lt;/p&gt;
&lt;p&gt;Most interesting part here was drag&#39;n&#39;drop to provide better user experience.&lt;/p&gt;
&lt;p&gt;I&#39;ve created the first version of this library and later it was handed over to
another developer.
It is one of the most valuable libraries at &lt;a href=&#34;https://qubequ.com&#34;&gt;QuBeQu&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;jquery-dashboard&#34;&gt;jQuery dashboard &lt;a class=&#34;header-anchor&#34; href=&#34;#jquery-dashboard&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One more client-side library created by me.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;I&#39;m expecting it to be published by &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; under the MIT license
(we had such an agreement)&lt;/s&gt;. It is &lt;a href=&#34;https://github.com/chtd/jquery.dashboard&#34;&gt;published&lt;/a&gt;
by &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; under the MIT license.&lt;/p&gt;
&lt;p&gt;The library is used to create custom layouts of reports and charts - for
dashboards.&lt;/p&gt;
&lt;p&gt;Drag&#39;n&#39;drop here too.&lt;/p&gt;
&lt;p&gt;There are more libraries and tasks I&#39;ve done working for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt;, a lot more.&lt;/p&gt;
&lt;h2 id=&#34;jython&#34;&gt;Jython &lt;a class=&#34;header-anchor&#34; href=&#34;#jython&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is one more subject I&#39;d like to talk about.&lt;/p&gt;
&lt;p&gt;We had an import/export functionality providing support for &lt;strong&gt;Excel&lt;/strong&gt; files
(among other formats).&lt;/p&gt;
&lt;p&gt;There were several &lt;strong&gt;python&lt;/strong&gt;-only solutions but we were not satisfied by them.
We needed a way to work with any &lt;strong&gt;xls/xlsx&lt;/strong&gt; file keeping its original
formatting untouched.&lt;/p&gt;
&lt;p&gt;One day I&#39;ve stumbled upon &lt;a href=&#34;http://poi.apache.org/&#34;&gt;POI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At first I was not sure we would be able to use it. I thought we need &lt;strong&gt;Java&lt;/strong&gt;
developer.&lt;/p&gt;
&lt;p&gt;But some time later I&#39;ve remembered about the &lt;a href=&#34;http://www.jython.org/&#34;&gt;Jython&lt;/a&gt; project.
It was an experiment and it was a success.&lt;/p&gt;
&lt;p&gt;I&#39;ve splitted the functionality into several parts.&lt;/p&gt;
&lt;p&gt;The first one was &lt;a href=&#34;http://www.jython.org/&#34;&gt;Jython&lt;/a&gt;-powered http service to work with &lt;strong&gt;Excel&lt;/strong&gt;
documents.&lt;/p&gt;
&lt;p&gt;The second one was &lt;strong&gt;python&lt;/strong&gt; library to communicate with this service and send
and receive data.&lt;/p&gt;
&lt;p&gt;And a bit later there was the third one - client-side import/export
configuration library providing a way to set parameters (we can read/write data
from/to different sheets and cells within &lt;strong&gt;Excel&lt;/strong&gt; documents).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://poi.apache.org/&#34;&gt;POI&lt;/a&gt;-based solution worked great and we had pretty good performance for
import/export operations.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary &lt;a class=&#34;header-anchor&#34; href=&#34;#summary&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was a good time. There were moments I was not satisfied with myself or
someone from colleagues but we are all human beings.&lt;/p&gt;
&lt;p&gt;We can and we must make mistakes - to be able to create something better.&lt;/p&gt;
&lt;p&gt;I have no opportunity but would love to work using &lt;a href=&#34;http://en.wikipedia.org/wiki/Lean_software_development&#34;&gt;Lean Software
Development&lt;/a&gt; principles.&lt;/p&gt;
&lt;p&gt;While developing sometimes it&#39;s better to think about optimisation ahead. You
must find a balance inside your mind between the desire to experiment and the
need to provide a solution in time.&lt;/p&gt;
&lt;p&gt;It&#39;s better to stay focused.&lt;/p&gt;
&lt;p&gt;It&#39;s important to form the team. Very important for the project.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Excellent article</title>
        <link href="https://ysegorov.github.io/2015/excellent-article/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/excellent-article/</id>
        <updated>2015-04-06T16:58:00+00:00</updated>
        <summary>Excellent article about programming</summary>
        <content type="html">
            &lt;h1 id=&#34;excellent-article&#34;&gt;Excellent article &lt;a class=&#34;header-anchor&#34; href=&#34;#excellent-article&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Really excellent &lt;a href=&#34;http://kukuruku.co/hub/programming/do-not-learn-frameworks-learn-the-architecture&#34;&gt;article&lt;/a&gt; (&lt;a href=&#34;http://habrahabr.ru/post/253297/&#34;&gt;original&lt;/a&gt; in Russian).&lt;/p&gt;
&lt;p&gt;Yesterday I&#39;ve summed up &lt;a href=&#34;https://ysegorov.github.io/2015/chtd/&#34;&gt;my experience&lt;/a&gt; working for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt;
and I have one more thought to share.&lt;/p&gt;
&lt;p&gt;It&#39;s just one more reason to minimize frameworks usage.&lt;/p&gt;
&lt;p&gt;From my experience frameworks are a trap. You can safely use them for some time
but in case your project is evolving and you want to follow the evolution of
used frameworks you will find yourself spending time refactoring your code to
work with that exact framework.&lt;/p&gt;
&lt;p&gt;Instead of developing your project&#39;s business logic you have to support
some framework code evolution.&lt;br /&gt;
It sounds strange for me.&lt;br /&gt;
I&#39;ve faced this problem working for &lt;a href=&#34;http://chtd.ru&#34;&gt;Chtd&lt;/a&gt; but I had no luck
explaining the problem to colleagues.&lt;/p&gt;
&lt;p&gt;There is a way to use framework - just freeze it on a specific version but
that&#39;s another trap.&lt;/p&gt;
&lt;p&gt;You will have to support framework at that specific
version on your own fixing bugs or adding missed functionality or backporting
or whatever. Do you really need it?&lt;/p&gt;
&lt;p&gt;I think it&#39;s better to spend time focusing on your business logic.&lt;/p&gt;
&lt;p&gt;To be a good developer you have to find your own way. Build something on
your own. Make mistakes. Fix them. Explore and share your knowledge.&lt;/p&gt;
&lt;p&gt;Become a creator, not a consumer.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Micro datetime parsing benchmark</title>
        <link href="https://ysegorov.github.io/2015/micro-datetime-parsing-benchmark/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/micro-datetime-parsing-benchmark/</id>
        <updated>2015-03-26T07:05:00+00:00</updated>
        <summary>Notes on datetime parsing in python2 to remember</summary>
        <content type="html">
            &lt;h1 id=&#34;micro-datetime-parsing-benchmark&#34;&gt;Micro datetime parsing benchmark &lt;a class=&#34;header-anchor&#34; href=&#34;#micro-datetime-parsing-benchmark&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Just a note for myself about datetime parsing in python.&lt;/p&gt;
&lt;p&gt;Let&#39;s assume we know ahead that we have a datetime string in &lt;a href=&#34;http://en.wikipedia.org/wiki/ISO_8601&#34;&gt;ISO 8601&lt;/a&gt;
format and timezone is &lt;a href=&#34;https://en.wikipedia.org/wiki/Coordinated_Universal_Time&#34;&gt;UTC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is a benchmark.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;In [1]: import arrow, re, datetime as dt

In [2]: iso = arrow.utcnow().isoformat()

In [3]: iso
Out[3]: &#39;2015-03-26T07:59:44.210642+00:00&#39;

In [4]: r = re.compile(r&#39;[\-T:\.]&#39;)

In [5]: arrow.get(iso)
Out[5]: &amp;lt;Arrow [2015-03-26T07:59:44.210642+00:00]&amp;gt;

In [6]: arrow.get(dt.datetime.strptime(iso.rpartition(&#39;+&#39;)[0], &#39;%Y-%m-%dT%H:%M:%S.%f&#39;), &#39;UTC&#39;)
Out[6]: &amp;lt;Arrow [2015-03-26T07:59:44.210642+00:00]&amp;gt;

In [7]: arrow.get(dt.datetime(*map(int, r.split(iso.rpartition(&#39;+&#39;)[0]))), &#39;UTC&#39;)
Out[7]: &amp;lt;Arrow [2015-03-26T07:59:44.210642+00:00]&amp;gt;

In [8]: %timeit arrow.get(iso)
10000 loops, best of 3: 54.7 µs per loop

In [9]: %timeit arrow.get(dt.datetime.strptime(iso.rpartition(&#39;+&#39;)[0], &#39;%Y-%m-%dT%H:%M:%S.%f&#39;), &#39;UTC&#39;)
100000 loops, best of 3: 17.5 µs per loop

In [10]: %timeit arrow.get(dt.datetime(*map(int, r.split(iso.rpartition(&#39;+&#39;)[0]))), &#39;UTC&#39;)
100000 loops, best of 3: 8.83 µs per loop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunatelly, the third way of parsing is wrong because it doesn&#39;t take into
account microseconds zero-padded to the left.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/crsmithdev/arrow&#34;&gt;Arrow&lt;/a&gt; library is just great and is certainly worth trying out.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Markdown preview</title>
        <link href="https://ysegorov.github.io/2015/markdown-live/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/markdown-live/</id>
        <updated>2015-03-31T12:02:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;markdown-preview&#34;&gt;Markdown preview &lt;a class=&#34;header-anchor&#34; href=&#34;#markdown-preview&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update 2.&lt;/strong&gt; I&#39;ve created &lt;a href=&#34;https://github.com/ysegorov/mdpreview-rs&#34;&gt;mdpreview&lt;/a&gt; project - self-made
solution to preview markdown files in browser. The code is written in Rust.
Short introduction is available &lt;a href=&#34;https://ysegorov.github.io/2020/mdpreview/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update 1.&lt;/strong&gt; For &lt;a href=&#34;http://docutils.sourceforge.net/rst.html&#34;&gt;reStructuredText&lt;/a&gt; there is an excellent &lt;a href=&#34;https://mg.pov.lt/restview/&#34;&gt;restview&lt;/a&gt;
library which works out-of-the-box.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It took half-a-workday time to find suitable solution to be able to somehow
preview rendered markdown files.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/&#34;&gt;GitHub&lt;/a&gt; uses &lt;a href=&#34;https://help.github.com/articles/github-flavored-markdown/&#34;&gt;GitHub Flavored Markdown&lt;/a&gt; so before committing
anything to the &lt;a href=&#34;https://github.com/ysegorov/jukoro/&#34;&gt;Jukoro&lt;/a&gt; reporsitory it would be great to take a quick
look at rendered markdown files.&lt;/p&gt;
&lt;p&gt;My editor of choice is &lt;a href=&#34;http://www.vim.org/&#34;&gt;vim&lt;/a&gt; and I have rather strong intension to keep it
as is.&lt;/p&gt;
&lt;p&gt;I prefer simple solutions meaning right after save I can see changes rendered
in browser (I don&#39;t need really live preview to see changes while typing).
Browser-based editors don&#39;t suit me due to the fact you have to edit a file in
browser.&lt;/p&gt;
&lt;p&gt;I looked at &lt;a href=&#34;https://atom.io/&#34;&gt;Atom&lt;/a&gt; and almost decided to use it but a small annoyance
forced me to look better for other ways (the annoyance is about caret
disappearing in editor after switching from and back to it).
For me there is one more problem with it.
I&#39;d like to turn off bold font in editor (the way I get used to working
in terminal) but I have no luck searching for this feature in preferences.&lt;/p&gt;
&lt;p&gt;There are several &lt;a href=&#34;https://nodejs.org/&#34;&gt;nodejs&lt;/a&gt;-based solutions but with most of them I had a
problem with live update (for some reason it was not working as expected by me).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/mobily/markdown-live&#34;&gt;markdown-live&lt;/a&gt; is the solution that I chose.
It works great and have a side panel to quickly switch between markdown-files.
Just great.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Jukoro documentation using Sphinx</title>
        <link href="https://ysegorov.github.io/2015/jukoro-docs-using-sphinx/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/jukoro-docs-using-sphinx/</id>
        <updated>2015-04-01T10:40:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;jukoro-documentation-using-sphinx&#34;&gt;Jukoro documentation using Sphinx &lt;a class=&#34;header-anchor&#34; href=&#34;#jukoro-documentation-using-sphinx&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; &lt;code&gt;jukoro&lt;/code&gt; library has been moved to archive, no plans to develop it further.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Summary about creating python library documentation using &lt;a href=&#34;http://sphinx-doc.org/&#34;&gt;Sphinx&lt;/a&gt; and
publishing it to &lt;a href=&#34;https://pages.github.com/&#34;&gt;GitHub Pages&lt;/a&gt; (based on &lt;a href=&#34;http://raxcloud.blogspot.co.uk/2013/02/documenting-python-code-using-sphinx.html&#34;&gt;this article&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ git clone git@github.com:ysegorov/jukoro.git
$ cd jukoro

$ mkdir docs
$ pip install sphinx
$ sphinx-apidoc -A &amp;quot;Yuri Egorov&amp;quot; -F -o docs jukoro

$ git add docs
$ git commit -m &amp;quot;sphinx-apidoc generated docs folder contents&amp;quot;

$ mkdir gh-pages
$ vim docs/Makefile  ## change BUILDDIR to ../gh-pages

$ /usr/share/git/workdir/git-new-workdir . gh-pages/html
$ cd gh-pages/html

$ git checkout --orphan gh-pages
$ git rm -rf .

$ cd ../../docs
$ make html
$ cd -

$ git add .
$ git commit -m &amp;quot;sphinx generated docs&amp;quot;
$ git push -u origin gh-pages

$ touch .nojekyll  ## to skip Jekyll
$ git add .nojekyll
$ git commit -m &amp;quot;.nojekyll&amp;quot;
$ git push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;s&gt;And now there is jukoro&#39;s documentation available online&lt;/s&gt; (still requires
some attention).&lt;/p&gt;
&lt;p&gt;For some reason I&#39;ve started &lt;a href=&#34;https://ysegorov.github.io/2015/markdown-live/&#34;&gt;to use markdown&lt;/a&gt; for &lt;code&gt;readme&lt;/code&gt; and &lt;code&gt;changelog&lt;/code&gt;
files but now it seems it would be better to use &lt;a href=&#34;http://docutils.sourceforge.net/rst.html&#34;&gt;reStructuredText&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This way it will be possible to include &lt;code&gt;readme&lt;/code&gt; and &lt;code&gt;changelog&lt;/code&gt; to
documentation (which is not finished yet).&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Jukoro 0.1.2 release</title>
        <link href="https://ysegorov.github.io/2015/jukoro-0.1.2/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/jukoro-0.1.2/</id>
        <updated>2015-04-06T17:01:00+00:00</updated>
        <summary>Jukoro promo</summary>
        <content type="html">
            &lt;h1 id=&#34;jukoro-012-release&#34;&gt;Jukoro 0.1.2 release &lt;a class=&#34;header-anchor&#34; href=&#34;#jukoro-012-release&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; This library has been moved to archive, no plans to develop it further.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It happened - first public release of &lt;a href=&#34;https://github.com/ysegorov/jukoro.git&#34;&gt;Jukoro&lt;/a&gt; (not on PyPi but still).&lt;/p&gt;
&lt;p&gt;It is an experiment and I&#39;ll do my best working on it.&lt;/p&gt;
&lt;h2 id=&#34;features-highlight-postgresql-focused&#34;&gt;Features highlight (PostgreSQL-focused) &lt;a class=&#34;header-anchor&#34; href=&#34;#features-highlight-postgresql-focused&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;unified tables structure in PostgreSQL storing data in a single per
table &lt;a href=&#34;http://www.postgresql.org/docs/9.4/static/datatype-json.html&#34;&gt;jsonb&lt;/a&gt; field&lt;/li&gt;
&lt;li&gt;out-of-the-box way to keep historical data in tables&lt;/li&gt;
&lt;li&gt;out-of-the-box support for &lt;code&gt;psycopg2&lt;/code&gt; named cursors&lt;/li&gt;
&lt;li&gt;single per-database sequence generator for objects identifiers&lt;/li&gt;
&lt;li&gt;out-of-the-box support for created/updated/deleted timestamps&lt;/li&gt;
&lt;li&gt;indices and constraints support for data stored in &lt;a href=&#34;http://www.postgresql.org/docs/9.4/static/datatype-json.html&#34;&gt;jsonb&lt;/a&gt; field&lt;/li&gt;
&lt;li&gt;connection to PostgreSQL always operate with timestamps in UTC&lt;/li&gt;
&lt;li&gt;PostgreSQL schema support&lt;/li&gt;
&lt;li&gt;way to introspect current database state&lt;/li&gt;
&lt;li&gt;way to prepare sql queries to synchronize database state and entities
(models) declarations (queries to create missed tables/indices/constraints
and to drop orphaned tables/indices/constraints)&lt;/li&gt;
&lt;li&gt;separation of concerns to work with PostgreSQL (explicit ways to work with
pool/connection/transaction/results,
to describe entities (models in terms of Django&#39;s ORM),
to introspect database,
to create customized sql queries)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;packages-and-modules&#34;&gt;Packages and modules &lt;a class=&#34;header-anchor&#34; href=&#34;#packages-and-modules&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jukoro.pg&lt;/code&gt; - package to work with PostgreSQL built on top of
&lt;a href=&#34;http://initd.org/psycopg/docs/&#34;&gt;psycopg2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.redis&lt;/code&gt; - package to work with Redis having several useful helpers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.arrow&lt;/code&gt; - package built on top of &lt;a href=&#34;http://crsmithdev.com/arrow/&#34;&gt;arrow&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.decorators&lt;/code&gt; - module containing some useful decorators&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.json&lt;/code&gt; - abstraction built on top of Python&#39;s stdlib &lt;code&gt;json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.pickle&lt;/code&gt; - abstraction built on top of Python&#39;s stdlib &lt;code&gt;cPickle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.base32&lt;/code&gt; - abstraction built on top of
&lt;a href=&#34;https://github.com/jbittel/base32-crockford&#34;&gt;base32_crockford&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.email&lt;/code&gt; - email helpers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.structures&lt;/code&gt; - some useful structures&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jukoro.utils&lt;/code&gt; - utilities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;s&gt;I am going to use it in project I&#39;m currently working on&lt;/s&gt; (it was never
used).&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Meet Juvi</title>
        <link href="https://ysegorov.github.io/2015/juvi/" rel="alternate" />
        <id>https://ysegorov.github.io/2015/juvi/</id>
        <updated>2015-06-29T08:44:00+00:00</updated>
        <summary>Introduction to Juvi - small client-side library</summary>
        <content type="html">
            &lt;h1 id=&#34;meet-juvi&#34;&gt;Meet Juvi &lt;a class=&#34;header-anchor&#34; href=&#34;#meet-juvi&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; This library has been moved to archive, no plans to develop it further.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;While working on a pet project I&#39;ve created a small client-side library
responsible (mostly) for a View part in MV* patterns and have named it
&lt;a href=&#34;https://github.com/ysegorov/juvi&#34;&gt;juvi&lt;/a&gt; (without any specific reason, just to have short name being
easy to remember).&lt;/p&gt;
&lt;p&gt;It is young and unstable but still looked pretty good for me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ysegorov/juvi&#34;&gt;Juvi&lt;/a&gt; depends on another library - &lt;a href=&#34;https://github.com/ysegorov/proto-js&#34;&gt;proto-js&lt;/a&gt; which is
a modified fork of Axel Rauschmayer&#39;s &lt;a href=&#34;https://github.com/rauschma/proto-js&#34;&gt;code&lt;/a&gt;.
The &lt;a href=&#34;http://www.2ality.com/2011/06/prototypes-as-classes.html&#34;&gt;idea&lt;/a&gt; behind
of &lt;strong&gt;proto-js&lt;/strong&gt; is very interesting and it&#39;s not clear to me why it&#39;s not as
popular as it should be.
Currently I&#39;m thinking about embedding &lt;strong&gt;proto-js&lt;/strong&gt; code to &lt;strong&gt;juvi&lt;/strong&gt; due to the
fact it&#39;s small and it will be easier to manage &lt;strong&gt;juvi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, coming back to &lt;strong&gt;juvi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Originally plan was to create something simple and extendable and to have the
following features included out-of-the-box:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;extendability (must be a way to extend view to keep code DRY and organized)&lt;/li&gt;
&lt;li&gt;unified way to render view&lt;/li&gt;
&lt;li&gt;unified way to attach event handlers to DOM&lt;/li&gt;
&lt;li&gt;unified way to declare, render and attach to DOM children views&lt;/li&gt;
&lt;li&gt;simple and reliable way to close view on its own and children views and
free resources&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is almost no magic inside &lt;a href=&#34;https://github.com/ysegorov/juvi/blob/develop/src/view.js&#34;&gt;view.js&lt;/a&gt;, just check the code (code can
speak, certainly).&lt;/p&gt;
&lt;p&gt;Probably, the most interesting part is &lt;strong&gt;handleEvent&lt;/strong&gt; method. Here is an
&lt;a href=&#34;http://www.thecssninja.com/javascript/handleevent&#34;&gt;article&lt;/a&gt; describing the
technique.&lt;/p&gt;
&lt;p&gt;And one more note about children views.&lt;/p&gt;
&lt;p&gt;Children views must be described in view instance as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// code can be placed into init method

this.children = {
    $title: TitleView(somePropsObject),
    $items: this.items.map(function (it) { return ItemView.new(it); })
};

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and DOM nodes as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// code should be placed into populateNodes method

var el = this.el,
    $ = this.$;         // NB. not a jQuery!

this.nodes = {
    $title: $(&#39;[data-title]&#39;, el),
    $items: $(&#39;[data-items]&#39;, el)
};

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having such a definitions view will automatically render all children views and
attach them to the specified DOM nodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;this.children.$title&lt;/strong&gt; view will be attached to &lt;strong&gt;this.nodes.$title&lt;/strong&gt; node&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;this.children.$items&lt;/strong&gt; views will be attached to &lt;strong&gt;this.nodes.$items&lt;/strong&gt; node
(keeping order)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no way to emit or listen for events per view because I&#39;m trying to
keep events flow organized in a &lt;strong&gt;Flux&lt;/strong&gt; way.
Here is the &lt;a href=&#34;https://github.com/ysegorov/juvi/blob/develop/src/dispatcher.js&#34;&gt;dispatcher.js&lt;/a&gt; - instance of
&lt;a href=&#34;https://github.com/ysegorov/juvi/blob/develop/src/pubsub.js&#34;&gt;pubsub.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And I almost forgot about this dependency - &lt;strong&gt;Promise&lt;/strong&gt;. It&#39;s up to you to
pick the one and include it in your project.
Currently I&#39;m using some parts of &lt;a href=&#34;https://github.com/zloirock/core-js&#34;&gt;core.js&lt;/a&gt;
library. Here is &lt;a href=&#34;https://github.com/jakearchibald/es6-promise&#34;&gt;es6-promise&lt;/a&gt;
polyfill suitable for &lt;strong&gt;pubsub&lt;/strong&gt; too.&lt;/p&gt;
&lt;p&gt;That&#39;s it.&lt;/p&gt;
&lt;p&gt;The mantra stays the same.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Become a creator, not a consumer.&lt;/strong&gt;&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Django project debugging</title>
        <link href="https://ysegorov.github.io/2016/django-debug/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/django-debug/</id>
        <updated>2016-01-17T12:32:00+00:00</updated>
        <summary>Simple tools to debug complex code</summary>
        <content type="html">
            &lt;h1 id=&#34;django-project-debugging&#34;&gt;Django project debugging &lt;a class=&#34;header-anchor&#34; href=&#34;#django-project-debugging&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Quite often there is a need to debug some code, to see what&#39;s going on and why
there is so much time spent generating pretty simple web page.&lt;/p&gt;
&lt;p&gt;There are tools making this task easier, &lt;a href=&#34;https://github.com/django-debug-toolbar/django-debug-toolbar&#34;&gt;django-debug-toolbar&lt;/a&gt; looks like
&lt;strong&gt;must have&lt;/strong&gt; debug swiss knife but I&#39;d like to use a self-made solution.&lt;/p&gt;
&lt;p&gt;I used to use logging as a way to get the information needed so &lt;a href=&#34;https://gist.github.com/ysegorov/7191601fd58bb37a9efd&#34;&gt;here are&lt;/a&gt;
two classes to debug code execution time and SQL queries and timings.
They can be used as decorators or as context managers (see below).&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/ysegorov/7191601fd58bb37a9efd.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;To initialize these classes you will have to pass &lt;code&gt;prefix&lt;/code&gt; as the only
argument (needed to grep logging output).&lt;/p&gt;
&lt;p&gt;Here are some abstract usage examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;
# -*- coding: utf-8 -*-

from django.shortcuts import render

from project.articles import get_articles, get_stats
from project.debug import timer, debug_sql


@debug_sql(&#39;index&#39;)
@timer(&#39;index&#39;)
def index(request):
    return render(request, &#39;index.html&#39;)


def articles(request):
    with timer(&#39;articles&#39;):
        articles = get_articles()
        with debug_sql(&#39;articles&#39;):
            stats = get_stats(articles)
    return render(request, &#39;articles.html&#39;, context={&#39;articles&#39;: articles,
                                                     &#39;stats&#39;: stats})

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s pretty easy to use the helpers, there is no need for a project-wide
configuration and you can focus on the code you are debugging to avoid logging
noise.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Webpack loader to use svg icons as snabbdom VNode</title>
        <link href="https://ysegorov.github.io/2016/svg-snabbdom-loader/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/svg-snabbdom-loader/</id>
        <updated>2016-07-04T08:45:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;webpack-loader-to-use-svg-icons-as-snabbdom-vnode&#34;&gt;Webpack loader to use svg icons as snabbdom VNode &lt;a class=&#34;header-anchor&#34; href=&#34;#webpack-loader-to-use-svg-icons-as-snabbdom-vnode&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; This library has been moved to archive, no plans to develop it further.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I&#39;m exploring FRP for frontend and it looks very interesting to me, especially
for dataflow using streams.&lt;/p&gt;
&lt;p&gt;Unidirectional data flow, introduced as &lt;strong&gt;Flux&lt;/strong&gt; by &lt;strong&gt;Facebook&lt;/strong&gt; engineers, is
an excellent paradigm and I was thinking about finding a way to use it without
&lt;strong&gt;React&lt;/strong&gt; (due to the fact I don&#39;t like it - just the same way I don&#39;t like
&lt;strong&gt;Angular&lt;/strong&gt; as both of them look overengineered to me).&lt;/p&gt;
&lt;p&gt;It took some time to understand the subject of FRP and there are a lot of
useful resources available (just a couple of links here - &lt;a href=&#34;https://www.gitbook.com/book/drboolean/mostly-adequate-guide/details&#34;&gt;Mostly Adequate
Guide to Functional Programming&lt;/a&gt;, &lt;a href=&#34;https://medium.com/@yelouafi/react-less-virtual-dom-with-snabbdom-functions-everywhere-53b672cb2fe3#.fnuaga25e&#34;&gt;React-less Virtual DOM with Snabbdom&lt;/a&gt;,
&lt;a href=&#34;https://gist.github.com/staltz/868e7e9bc2a7b8c1f754&#34;&gt;The introduction to Reactive Programming&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;My first attempt was to understand &lt;a href=&#34;https://github.com/paldepind/snabbdom&#34;&gt;snabbdom&lt;/a&gt; / &lt;a href=&#34;https://github.com/paldepind/flyd&#34;&gt;flyd&lt;/a&gt; /
&lt;a href=&#34;https://github.com/paldepind/union-type&#34;&gt;union-type&lt;/a&gt; / &lt;a href=&#34;https://github.com/ramda/ramda&#34;&gt;ramda&lt;/a&gt; approach and the most challenging
part was &lt;strong&gt;union types&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Studying &lt;a href=&#34;http://guide.elm-lang.org/architecture/index.html&#34;&gt;The ELM Architecture&lt;/a&gt; helped a lot in this.&lt;/p&gt;
&lt;p&gt;To dive deeper on the subject I&#39;ve created a very simple implementation of
union types which in it&#39;s core just tags values using specified tag name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// type.js

var curryN = require(&#39;ramda/src/curryN&#39;);

function Type(spec) {
    var o = {},
        keys = Object.keys(spec);

    keys.forEach(function (key) {
        var fn = spec[key];
        if (spec[key].length &amp;gt; 2) {
            o[key] = curryN(fn.length - 1, function () {
                return {
                    value: [].slice.apply(arguments),
                    tag: key,
                    handler: fn
                };
            });
        } else {
            o[key] = function (smth) {
                return {
                    value: smth,
                    tag: key,
                    handler: fn
                };
            };
        }
    });
    function update(tagged, model) {
        var tag = tagged.tag,
            value = tagged.value,
            fn = tagged.handler;
        value = Array.isArray(value) ? value
                                        : (value != null ? [value] : []);
        value.push(model);
        return fn.apply(null, value);
    }
    o.update = curryN(2, update);
    return o;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example of union type definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// component.js

var Type = require(&#39;./type&#39;);
var R = require(&#39;ramda&#39;);

var Msg = Type({
    Click: function (evt, model) { return R.assoc(&#39;clicks&#39;, model.clicks + 1, model); },
    Remove: function (evt, model) { return R.assoc(&#39;_removed&#39;, true, model); },
    Tick: function (model) {
        return R.assoc(&#39;count&#39;, model.count &amp;gt; 359 ? 0 : model.count + 1, model);
    }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a bit simplier than &lt;a href=&#34;https://github.com/paldepind/union-type&#34;&gt;union-type&lt;/a&gt;, doesn&#39;t have type checking and
probably missing something in this implementation.&lt;/p&gt;
&lt;p&gt;Anyway, it helped me to understand the data flow.&lt;/p&gt;
&lt;p&gt;My experiments are available in &lt;a href=&#34;https://github.com/ysegorov/vdom-experiment&#34;&gt;this project&lt;/a&gt;
(work in progress).&lt;/p&gt;
&lt;p&gt;I like to use svg icons for ui components and I used to create separate
html file with all icons embedded in it using single &lt;strong&gt;svg&lt;/strong&gt; and multiple
&lt;strong&gt;symbol&lt;/strong&gt; definitions and referencing them using &lt;strong&gt;xlink:href&lt;/strong&gt; attribute.&lt;/p&gt;
&lt;p&gt;I was planning to use icons to enrich the ui of the experiments and thought it
would be great to have &lt;strong&gt;svg&lt;/strong&gt; icons available as &lt;a href=&#34;https://github.com/paldepind/snabbdom&#34;&gt;snabbdom&lt;/a&gt; &lt;strong&gt;VNodes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, here is &lt;a href=&#34;https://github.com/ysegorov/svg-snabbdom-loader&#34;&gt;the webpack loader&lt;/a&gt; for this (this is my first published
&lt;strong&gt;npm&lt;/strong&gt; module).&lt;/p&gt;
&lt;p&gt;Usage is pretty simple just like any webpack loader:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// icons.js

var home = require(&#39;./svg/home.svg&#39;),
    alert = require(&#39;./svg/alert.svg&#39;),
    ...

module.exports = {
    home: home,
    alert: alert,
    ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// alerts.js

var icons = require(&#39;./icons&#39;),
    h = require(&#39;snabbdom/h&#39;);

function view(model) {
    return h(&#39;div.info&#39;, {}, [icons.alert, &#39;Some alert here&#39;]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The loader can be chained with &lt;strong&gt;svgo-loader&lt;/strong&gt;, please check the docs for this.&lt;/p&gt;
&lt;p&gt;That&#39;s it for now.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Alcor Micro AU6601 PCI-E Flash card reader controller</title>
        <link href="https://ysegorov.github.io/2016/au6601/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/au6601/</id>
        <updated>2016-09-30T05:16:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;alcor-micro-au6601-pci-e-flash-card-reader-controller-on-archlinux&#34;&gt;Alcor Micro AU6601 PCI-E Flash card reader controller on ArchLinux &lt;a class=&#34;header-anchor&#34; href=&#34;#alcor-micro-au6601-pci-e-flash-card-reader-controller-on-archlinux&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; Please check &lt;a href=&#34;https://ysegorov.github.io/2018/au6601-2/&#34;&gt;this post&lt;/a&gt; for installation instructions for
Linux kernel 4.16+.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I&#39;m running &lt;a href=&#34;https://archlinux.org&#34;&gt;ArchLinux&lt;/a&gt; on this &lt;a href=&#34;https://www.asus.com/Commercial-Notebooks/ASUSPRO_ADVANCED_BU401LG/&#34;&gt;perfect ASUSPRO BU401LG notebook&lt;/a&gt;
by ASUS and the only problem I faced recently was sd-card reader
not working at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lspci&lt;/code&gt;&lt;/strong&gt; shows the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;
$ lspci
00:00.0 Host bridge: Intel Corporation Haswell-ULT DRAM Controller (rev 09)
00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 09)
00:03.0 Audio device: Intel Corporation Haswell-ULT HD Audio Controller (rev 09)
00:04.0 Signal processing controller: Intel Corporation Device 0a03 (rev 09)
00:16.0 Communication controller: Intel Corporation 8 Series HECI #0 (rev 04)
00:19.0 Ethernet controller: Intel Corporation Ethernet Connection I218-V (rev 04)
00:1b.0 Audio device: Intel Corporation 8 Series HD Audio Controller (rev 04)
00:1c.0 PCI bridge: Intel Corporation 8 Series PCI Express Root Port 1 (rev e4)
00:1c.1 PCI bridge: Intel Corporation 8 Series PCI Express Root Port 2 (rev e4)
00:1c.3 PCI bridge: Intel Corporation 8 Series PCI Express Root Port 4 (rev e4)
00:1c.4 PCI bridge: Intel Corporation 8 Series PCI Express Root Port 5 (rev e4)
00:1d.0 USB controller: Intel Corporation 8 Series USB EHCI #1 (rev 04)
00:1f.0 ISA bridge: Intel Corporation 8 Series LPC Controller (rev 04)
00:1f.2 SATA controller: Intel Corporation 8 Series SATA Controller 1 [AHCI mode] (rev 04)
00:1f.3 SMBus: Intel Corporation 8 Series SMBus Controller (rev 04)
00:1f.6 Signal processing controller: Intel Corporation 8 Series Thermal (rev 04)
02:00.0 Unassigned class [ff00]: Alcor Micro AU6601 PCI-E Flash card reader controller
03:00.0 Network controller: Intel Corporation Wireless 7260 (rev 6b)
04:00.0 3D controller: NVIDIA Corporation GK208M [GeForce GT 730M] (rev a1)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are no events in logs after inserting sd-card into slot. So, after a bit
of searching here is the solution.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&#34;https://launchpad.net/~iacobs&#34;&gt;Sabin Iacob&lt;/a&gt; there is a &lt;a href=&#34;https://launchpad.net/~iacobs/+archive/ubuntu/au6601&#34;&gt;driver&lt;/a&gt; for the card reader
and the only thing to do is to install it.&lt;/p&gt;
&lt;p&gt;Driver is packaged for Ubuntu and these are the steps I&#39;ve done to install
it on Arch:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;download appropriate &lt;a href=&#34;https://launchpad.net/~iacobs/+archive/ubuntu/au6601/+files/au6601-dkms_0.3-0~ppa7_amd64.deb&#34;&gt;deb-package&lt;/a&gt; (i386 or amd64)
from &lt;a href=&#34;https://launchpad.net/~iacobs/+archive/ubuntu/au6601/+packages&#34;&gt;packages&lt;/a&gt; page&lt;/li&gt;
&lt;li&gt;install &lt;code&gt;debtap&lt;/code&gt; package from AUR if not already installed&lt;/li&gt;
&lt;li&gt;initialize &lt;code&gt;debtap&lt;/code&gt; database&lt;/li&gt;
&lt;li&gt;convert deb package to archlinux package using &lt;code&gt;debtap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;install generated package using &lt;code&gt;yaourt -U&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;install kernel driver&lt;/li&gt;
&lt;li&gt;use card reader :)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;
$ wget https://launchpad.net/~iacobs/+archive/ubuntu/au6601/+files/au6601-dkms_0.3-0~ppa7_amd64.deb
$ yaourt -S debtap
$ sudo debtap -u
$ debtap au6601-dkms_0.3-0-ppa7_amd64.deb
$ yaourt -U au6601-dkms-0.3-1-x86_64.pkg.tar.xz
$ sudo modprobe au6601-pci
$ udevil mount /dev/mmcblk0p1

# profit!

&lt;/code&gt;&lt;/pre&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>DO</title>
        <link href="https://ysegorov.github.io/2016/do/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/do/</id>
        <updated>2016-10-11T07:55:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;do&#34;&gt;DO &lt;a class=&#34;header-anchor&#34; href=&#34;#do&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Not long ago reading some news I&#39;ve read about &lt;a href=&#34;http://letterslive.com/&#34;&gt;Letters Live&lt;/a&gt;
project and looking through the letters I&#39;ve came to a brilliant one.&lt;/p&gt;
&lt;p&gt;Certainly, this letter is very impressive and powerfull and I want to keep it
here.&lt;/p&gt;
&lt;p&gt;Text is taken from correspondent &lt;a href=&#34;http://letterslive.com/&#34;&gt;Letters Live&lt;/a&gt; page and you
definitely should &lt;a href=&#34;http://letterslive.com/letter/do/&#34;&gt;go there&lt;/a&gt; to watch the video.&lt;/p&gt;
&lt;h2 id=&#34;letter-from-sol-lewitt-to-eva-hesse-april-14-1965&#34;&gt;Letter from Sol LeWitt to Eva Hesse, April 14, 1965 &lt;a class=&#34;header-anchor&#34; href=&#34;#letter-from-sol-lewitt-to-eva-hesse-april-14-1965&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear Eva,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It will be almost a month since you wrote to me and you have possibly
forgotten your state of mind (I doubt it though).
You seem the same as always, and being you, hate every minute of it.
Don’t! Learn to say “Fuck You” to the world once in a while.
You have every right to. Just stop thinking, worrying, looking over your
shoulder, wondering, doubting, fearing, hurting,
hoping for some easy way out, struggling, grasping, confusing,
itching, scratching, mumbling, bumbling, grumbling, humbling,
stumbling, numbling, rambling, gambling, tumbling, scumbling,
scrambling, hitching, hatching, bitching, moaning, groaning,
honing, boning, horse-shitting, hair-splitting, nit-picking,
piss-trickling, nose sticking, ass-gouging, eyeball-poking,
finger-pointing, alleyway-sneaking, long waiting, small stepping,
evil-eyeing, back-scratching, searching, perching, besmirching,
grinding, grinding, grinding away at yourself. Stop it and just&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;DO&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;From your description, and from what I know of your previous work
and your ability; the work you are doing sounds very good
“Drawing – clean – clear but crazy like machines,
larger and bolder… real nonsense.”
That sounds fine, wonderful — real nonsense.
Do more. More nonsensical, more crazy, more machines, more breasts,
penises, cunts, whatever — make them abound with nonsense.
Try and tickle something inside you, your “weird humor.”
You belong in the most secret part of you.
Don’t worry about cool, make your own uncool.
Make your own, your own world.
If you fear, make it work for you — draw &amp;amp; paint your fear &amp;amp; anxiety.
And stop worrying about big, deep things such as
“to decide on a purpose and way of life, a consistant approach
to even some impossible end or even an imagined end.”
You must practice being stupid, dumb, unthinking, empty.
Then you will be able to&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;DO&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I have much confidence in you and even though you are tormenting yourself,
the work you do is very good. Try to do some BAD work —
the worst you can think of and see what happens but mainly relax
and let everything go to hell —
you are not responsible for the world —
you are only responsible for your work — so DO IT.
And don’t think that your work has to conform to any preconceived
form, idea or flavor.
It can be anything you want it to be.
But if life would be easier for you if you stopped working — then stop.
Don’t punish yourself.
However, I think that it is so deeply engrained in you that
it would be easier to&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;DO&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It seems I do understand your attitude somewhat, anyway,
because I go through a similar process every so often.
I have an “Agonizing Reappraisal” of my work and change
everything as much as possible — and hate everything I’ve done,
and try to do something entirely different and better.
Maybe that kind of process is necessary to me, pushing me on and on.
The feeling that I can do better than that shit I just did.
Maybe you need your agony to accomplish what you do.
And maybe it goads you on to do better.
But it is very painful I know.
It would be better if you had the confidence just to do the stuff
and not even think about it.
Can’t you leave the “world” and “ART” alone and also quit fondling your ego.
I know that you (or anyone) can only work so much
and the rest of the time you are left with your thoughts.
But when you work or before your work you have to empty
your mind and concentrate on what you are doing.
After you do something it is done and that’s that.
After a while you can see some are better than others
but also you can see what direction you are going.
I’m sure you know all that.
You also must know that you don’t have to justify your work —
not even to yourself.
Well, you know I admire your work greatly and can’t understand
why you are so bothered by it. But you can see the next ones &amp;amp; I can’t.
You also must believe in your ability.
I think you do.
So try the most outrageous things you can — shock yourself.
You have at your power the ability to do anything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I would like to see your work and will have to be content to wait
until Aug or Sept.
I have seen photos of some of Tom’s new things at Lucy’s.
They are very impressive — especially the ones with the more rigorous form;
the simpler ones. I guess he’ll send some more later on.
Let me know how the shows are going and that kind of stuff.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;My work has changed since you left and it is much better.
I will be having a show May 4–29
at the Daniels Gallery 17 E 64th St (where Emmerich was),
I wish you could be there.
Much love to you both.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Sol&lt;/p&gt;
&lt;/blockquote&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Pipeline As a Code With Jenkins</title>
        <link href="https://ysegorov.github.io/2016/jenkinsfile/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/jenkinsfile/</id>
        <updated>2016-12-27T10:45:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;pipeline-as-a-code-with-jenkins&#34;&gt;Pipeline as a code with Jenkins &lt;a class=&#34;header-anchor&#34; href=&#34;#pipeline-as-a-code-with-jenkins&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://jenkins.io/&#34;&gt;Jenkins&lt;/a&gt; has a pretty nice &lt;a href=&#34;https://jenkins.io/solutions/pipeline/&#34;&gt;Pipeline&lt;/a&gt; plugin to manage build, test and
deploy steps in a single file named &lt;code&gt;Jenkinsfile&lt;/code&gt;. This file should be stored
alongside with the project code just like &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;javascript&lt;/code&gt;, &lt;code&gt;html&lt;/code&gt; or
whatever files.&lt;/p&gt;
&lt;p&gt;The only problem with &lt;code&gt;Jenkinsfile&lt;/code&gt; is that it must be written in &lt;a href=&#34;http://www.groovy-lang.org/&#34;&gt;Groovy&lt;/a&gt;.
To me this is the same problem as with &lt;code&gt;Vagrantfile&lt;/code&gt; which must be written in
&lt;a href=&#34;https://www.ruby-lang.org/en/&#34;&gt;Ruby&lt;/a&gt;.
There is something strange forcing users to study language in order to have
proper configuration file.&lt;/p&gt;
&lt;p&gt;It took some time to prepare workable &lt;code&gt;Jenkinsfile&lt;/code&gt; which works for
&lt;a href=&#34;https://jenkins.io/blog/2015/12/03/pipeline-as-code-with-multibranch-workflows-in-jenkins/&#34;&gt;Multibranch Workflows&lt;/a&gt; so I decided to create a &lt;a href=&#34;https://gist.github.com/ysegorov/a23e7324e264b9afd932bd8b90862305&#34;&gt;gist&lt;/a&gt; with it.&lt;/p&gt;
&lt;p&gt;Here it is:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/ysegorov/a23e7324e264b9afd932bd8b90862305.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;It works pretty good for me providing slack notifications to production or
staging channels and having links to &lt;a href=&#34;https://bitbucket.org&#34;&gt;Bitbucket&lt;/a&gt; diff page to see changes
commited between builds.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;Jenkinsfile&lt;/code&gt; is suitable for &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;nodejs&lt;/code&gt; projects and requires
just minimal tuning - to provide proper &lt;em&gt;repository name and url&lt;/em&gt; and &lt;em&gt;build,
test and deploy&lt;/em&gt; commands for the project.
Deployment happens only for &lt;code&gt;develop&lt;/code&gt; (staging server) and &lt;code&gt;master&lt;/code&gt; (production
server) branches.&lt;/p&gt;
&lt;p&gt;Hope somebody will find this &lt;a href=&#34;https://gist.github.com/ysegorov/a23e7324e264b9afd932bd8b90862305&#34;&gt;gist&lt;/a&gt; usefull.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Self-made Virtualenv Wrapper</title>
        <link href="https://ysegorov.github.io/2016/virtualenv/" rel="alternate" />
        <id>https://ysegorov.github.io/2016/virtualenv/</id>
        <updated>2016-12-28T08:27:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;self-made-virtualenv-wrapper&#34;&gt;Self-made Virtualenv Wrapper &lt;a class=&#34;header-anchor&#34; href=&#34;#self-made-virtualenv-wrapper&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Not long ago I&#39;ve switched from &lt;a href=&#34;https://pypi.python.org/pypi/virtualenvwrapper&#34;&gt;virtualenvwrapper&lt;/a&gt; to self-made solution
based on &lt;a href=&#34;https://gist.github.com/datagrok/2199506&#34;&gt;this idea&lt;/a&gt; by &lt;a href=&#34;http://datagrok.org/&#34;&gt;datagrok&lt;/a&gt;.
It works pretty well for me and I&#39;d like to share it here.&lt;/p&gt;
&lt;p&gt;The idea is to have a &lt;em&gt;root&lt;/em&gt; directory (&lt;code&gt;$HOME/_dev&lt;/code&gt; in my case)
for all projects and to have shell helper to easily jump into any project
and to automatically activate it&#39;s &lt;a href=&#34;https://github.com/pypa/virtualenv&#34;&gt;virtualenv&lt;/a&gt; if it exists.&lt;/p&gt;
&lt;p&gt;Here is how it looks in &lt;code&gt;bash&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
[local] [egorov@asus 11:33:19]:~  $ dev blog
Virtual environment found in /home/egorov/_dev/blog/env, activated.
(blog) [local] [egorov@asus 11:34:31]:~/_dev/blog git:master= $

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Besides just jumping into directory I wanted to have &lt;code&gt;tab&lt;/code&gt; autocompletion and
easy way to create new projects &lt;code&gt;home&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
# autocompletion
[local] [egorov@asus 11:43:01]:~  $ dev service-  # tab hitted twice
service-account   service-feedback  service-products  service-workers

# new project home
[local] [egorov@asus 11:52:08]:~  $ dev rogue
mkdir: created directory &#39;/home/egorov/_dev/rogue&#39;
No virtual environment found, skipping activate.
[local] [egorov@asus 11:52:25]:~/_dev/rogue  $

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, here are &lt;code&gt;bash&lt;/code&gt; helpers which should be placed somewhere inside &lt;code&gt;~/.bashrc&lt;/code&gt;
or &lt;code&gt;~/.bash_profile&lt;/code&gt; (mine lives &lt;a href=&#34;https://github.com/ysegorov/dotfiles/blob/master/.bash.d/dev&#34;&gt;there&lt;/a&gt;).
&lt;code&gt;_dev&lt;/code&gt; function depends on &lt;code&gt;inve&lt;/code&gt; shell script which must be available
in &lt;code&gt;PATH&lt;/code&gt; (I have &lt;code&gt;$HOME/bin&lt;/code&gt; in &lt;code&gt;PATH&lt;/code&gt; for this and &lt;code&gt;inve&lt;/code&gt; lives &lt;a href=&#34;https://github.com/ysegorov/dotfiles/blob/master/bin/inve&#34;&gt;there&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
# dev
DEV=${HOME}/_dev  # home for all projects

_dev() {
    local p=${DEV}/$1
    [ ! -d $p ] &amp;amp;&amp;amp; mkdir $p
    cd $p
    inve  # binary file to be accessible in PATH
    return 0
}
_dev_complete()
{
    local cur prev opts
    local p=${DEV}
    [ ! -d $p ] &amp;amp;&amp;amp; `which mkdir` $p
    COMPREPLY=()
    cur=&amp;quot;${COMP_WORDS[COMP_CWORD]}&amp;quot;
    prev=&amp;quot;${COMP_WORDS[COMP_CWORD-1]}&amp;quot;
    opts=`cd $p &amp;amp;&amp;amp; find -L . -maxdepth 1 -type d | sed &#39;s|[\./]||g&#39;`

    COMPREPLY=( $(compgen -W &amp;quot;${opts}&amp;quot; -- ${cur}) )
}
alias dev=_dev
complete -F _dev_complete dev

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;inve&lt;/code&gt; executable content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
#!/usr/bin/env bash

# tuned idea from: https://gist.github.com/datagrok/2199506
#
# inve
#
# For use with Ian Bicking&#39;s virtualenv tool. Attempts to find the root of
# a virtual environment and activate it in subshell.

# First, locate the root of the current virtualenv
cwd=$PWD
export DEV_ROOT=$cwd

while [ &amp;quot;$PWD&amp;quot; != &amp;quot;/&amp;quot; ]; do
    # Stop here if this the root of a virtualenv
    # will look for virtualenv in `current dir` or in `env` subdirectory
    if [ \
        -x bin/python \
        -a -e lib/python*/site.py \
        -a -e include/python*/Python.h ]
    then
        export VIRTUAL_ENV=&amp;quot;$PWD&amp;quot;
        break
    elif [ \
        -x env/bin/python \
        -a -e env/lib/python*/site.py \
        -a -e env/include/python*/Python.h ]
    then
        export VIRTUAL_ENV=&amp;quot;$PWD/env&amp;quot;
        break
    fi
    cd ..
done
if [ &amp;quot;$PWD&amp;quot; = &amp;quot;/&amp;quot; ]; then
    export PATH=&amp;quot;$cwd/node_modules/.bin:$PATH&amp;quot;
    echo &amp;quot;No virtual environment found, skipping activate.&amp;quot; &amp;gt;&amp;amp;2
    cd $cwd
else
    # Activate
    export PATH=&amp;quot;$VIRTUAL_ENV/bin:$cwd/node_modules/.bin:$PATH&amp;quot;
    unset PYTHONHOME
    echo &amp;quot;Virtual environment found in ${VIRTUAL_ENV}, activated.&amp;quot; &amp;gt;&amp;amp;2
fi
exec &amp;quot;$SHELL&amp;quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;inve&lt;/code&gt; script looks for &lt;code&gt;virtualenv&lt;/code&gt; in &lt;code&gt;env&lt;/code&gt; subdirectory or attempts to
find it somewhere upper in the filesystem tree. It modifies &lt;code&gt;PATH&lt;/code&gt; prepending
&lt;code&gt;$VIRTUALENV/bin&lt;/code&gt; and &lt;code&gt;node_modules/.bin&lt;/code&gt; directories and starts new shell.
I like the idea of starting a new subshell in order to activate &lt;code&gt;virtualenv&lt;/code&gt; as
this way we can be sure there will be no problems with &lt;code&gt;PATH&lt;/code&gt; within shell and
it&#39;s pretty safe to exit this subshell and have parent shell clean as it should
be.&lt;/p&gt;
&lt;p&gt;To easily navigate to some directories within activated &lt;code&gt;virtualenv&lt;/code&gt; I have a
couple of bash aliases defined:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
alias cdsrc=&#39;cd ${VIRTUAL_ENV}/src&#39;
alias cdsitepackages=&#39;cd ${VIRTUAL_ENV}/lib/python*/site-packages/&#39;
alias cdproject=&#39;cd ${DEV_ROOT:-VIRTUAL_ENV}; if [ `basename ${PWD}` = &amp;quot;env&amp;quot; ]; then cd ..; fi&#39;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach allows me to have virtual environments using &lt;code&gt;python2&lt;/code&gt; or
&lt;code&gt;python3&lt;/code&gt; under single &lt;em&gt;root&lt;/em&gt; directory and to have single tool to jump into
project be it &lt;code&gt;python2&lt;/code&gt;, &lt;code&gt;python3&lt;/code&gt; or even &lt;code&gt;nodejs&lt;/code&gt; project.&lt;/p&gt;
&lt;p&gt;Everything works pretty good for me.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Static blog generator</title>
        <link href="https://ysegorov.github.io/2017/wt/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/wt/</id>
        <updated>2026-07-26T11:41:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;static-blog-generator&#34;&gt;Static Blog Generator &lt;a class=&#34;header-anchor&#34; href=&#34;#static-blog-generator&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;strong&gt;Update 1.&lt;/strong&gt; This library has been moved to archive, no plans to develop it further&lt;/s&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2.&lt;/strong&gt; This library was unarchived, rebuilt from scratch and released as 3.0.0 version.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is a short introduction to &lt;a href=&#34;https://codeberg.org/ysegorov/wt&#34;&gt;wt&lt;/a&gt; - library I&#39;ve made for my personal
use.&lt;/p&gt;
&lt;p&gt;It is pretty young and it lacks some features I&#39;d like it to have but it
works pretty good for me.&lt;/p&gt;
&lt;p&gt;So, this is &lt;a href=&#34;http://docs.getpelican.com/&#34;&gt;yet&lt;/a&gt; &lt;a href=&#34;https://grow.io/&#34;&gt;another&lt;/a&gt; &lt;a href=&#34;http://jekyllrb.com/&#34;&gt;static&lt;/a&gt; &lt;a href=&#34;https://hexo.io/&#34;&gt;site&lt;/a&gt;/&lt;a href=&#34;http://wintersmith.io/&#34;&gt;blog&lt;/a&gt;
&lt;a href=&#34;http://gohugo.io/&#34;&gt;generator&lt;/a&gt;. Yes. One more.&lt;/p&gt;
&lt;p&gt;Some time ago I thought it would be great to build something for my own use. I
have several ideas and this is the first one named &lt;strong&gt;wt&lt;/strong&gt;.
I know that &lt;strong&gt;wt&lt;/strong&gt; is a name for executable from &lt;a href=&#34;https://github.com/wiredtiger/wiredtiger&#34;&gt;WiredTiger&lt;/a&gt;
distribution but I think it&#39;s ok. This library is not expected to be installed
system-wide, it should be used within virtual environment.
And luckily the name was free on &lt;a href=&#34;https://pypi.org/project/wt&#34;&gt;pypi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The library requires &lt;strong&gt;python 3&lt;/strong&gt; and have the following features (citing from
&lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/README.md&#34;&gt;readme&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://daringfireball.net/projects/markdown/&#34;&gt;markdown&lt;/a&gt; for content&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://yaml.org/&#34;&gt;yaml&lt;/a&gt; for configuration&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://jinja.pocoo.org/&#34;&gt;jinja2&lt;/a&gt; for templating&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Atom_(standard)&#34;&gt;atom&lt;/a&gt; for feed&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://aiohttp.readthedocs.io/en/stable/&#34;&gt;aiohttp&lt;/a&gt; for development server&lt;/li&gt;
&lt;li&gt;only two types of content - &lt;strong&gt;page&lt;/strong&gt; and &lt;strong&gt;post&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;content metadata lives in configuration file&lt;/li&gt;
&lt;li&gt;have sensible defaults for content sources&lt;/li&gt;
&lt;li&gt;no python coding needed to work with&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the moment I&#39;ve used it in a couple of projects.&lt;/p&gt;
&lt;p&gt;The first one is this blog (&lt;a href=&#34;https://codeberg.org/ysegorov/blog&#34;&gt;blog source code&lt;/a&gt;) and another one
is the &lt;a href=&#34;https://tolsha.ru/&#34;&gt;tolsha.ru site&lt;/a&gt; (in Russian) I&#39;ve created for my elder
brother who makes &lt;a href=&#34;https://en.wikipedia.org/wiki/Pottery&#34;&gt;pottery&lt;/a&gt; and &lt;a href=&#34;https://tolsha.ru/util/&#34;&gt;they&lt;/a&gt; &lt;a href=&#34;https://tolsha.ru/milk/chasha_lebed/&#34;&gt;are&lt;/a&gt; &lt;a href=&#34;https://tolsha.ru/souvenirs/&#34;&gt;amazing&lt;/a&gt;
(&lt;a href=&#34;https://github.com/ysegorov/tolsha.ru&#34;&gt;site source code&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;These two sites are pretty different in nature but &lt;a href=&#34;https://codeberg.org/ysegorov/wt&#34;&gt;wt&lt;/a&gt; works very well for
both.&lt;/p&gt;
&lt;p&gt;I&#39;ll keep this library moving forward adding more features and refactoring
some internals for a better code.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;The next project I have plans for is &lt;strong&gt;rss reader&lt;/strong&gt; and there is a big chance
I&#39;ll build it using &lt;a href=&#34;http://elixir-lang.org/&#34;&gt;Elixir&lt;/a&gt;/&lt;a href=&#34;http://www.phoenixframework.org/&#34;&gt;Phoenix&lt;/a&gt;&lt;/s&gt; (not happened).&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Logger service using epoll - Part 1</title>
        <link href="https://ysegorov.github.io/2017/logger/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/logger/</id>
        <updated>2017-03-24T06:45:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;logger-service-using-epoll---part-1&#34;&gt;Logger service using epoll - Part 1 &lt;a class=&#34;header-anchor&#34; href=&#34;#logger-service-using-epoll---part-1&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; There is a &lt;a href=&#34;https://ysegorov.github.io/2017/logger-2/&#34;&gt;continuation&lt;/a&gt; of this post.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Suppose we have a number of microservices and we need some way to easily handle
logging from all of them.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.graylog.org/&#34;&gt;Graylog&lt;/a&gt; might be a good choice but in case you don&#39;t
need such a full-featured solution self-made logging service can serve you well.&lt;/p&gt;
&lt;p&gt;Python&#39;s &lt;a href=&#34;https://docs.python.org/2/library/logging.html&#34;&gt;logging&lt;/a&gt; facility has almost everything we need for this providing
&lt;a href=&#34;https://docs.python.org/2/library/logging.handlers.html#sockethandler&#34;&gt;SocketHandler&lt;/a&gt; to send log records to a network socket. The missed part is
actual logging service which will be able to receive and save those records.
&lt;a href=&#34;https://docs.python.org/2/howto/logging-cookbook.html&#34;&gt;Logging Cookbook&lt;/a&gt; contains &lt;a href=&#34;https://docs.python.org/2/howto/logging-cookbook.html#sending-and-receiving-logging-events-across-a-network&#34;&gt;basic implementation&lt;/a&gt; of such a service
which is good for a quick start.&lt;/p&gt;
&lt;p&gt;I was experimenting with &lt;a href=&#34;https://github.com/dabeaz/curio&#34;&gt;curio&lt;/a&gt; as an engine for such a service and it
worked pretty well and certainly might be a good choice for this task. The only
thing forced me to look for another solution was it&#39;s Python 3 dependency. All
microservices I need logging service for are using Python 2 and I&#39;d like
it to use the very same python.&lt;/p&gt;
&lt;p&gt;So, after a bit more experiments I came up with &lt;strong&gt;edge-triggered epoll-based&lt;/strong&gt;
solution which is compatible with Python 2 and Python 3.
The code for the service is available &lt;a href=&#34;https://gist.github.com/ysegorov/8947d99a016aa00ace51d9ab4d89c428&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It took some time to understand &lt;a href=&#34;http://man7.org/linux/man-pages/man7/epoll.7.html&#34;&gt;epoll&lt;/a&gt; mechanics and &lt;a href=&#34;http://scotdoyle.com/python-epoll-howto.html&#34;&gt;this article&lt;/a&gt;
by Scot Doyle helped a lot. My local test confirms service is pretty stable and
properly handle incoming logging records.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://gist.github.com/ysegorov/8947d99a016aa00ace51d9ab4d89c428&#34;&gt;Code in gist&lt;/a&gt; is rather generic and I&#39;m going to add some features, but
they won&#39;t be published there, sorry for that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use some &lt;em&gt;magic&lt;/em&gt; number in message header as a simple measure to prevent
unknown clients from spamming (even though the service will listen on
localhost)&lt;/li&gt;
&lt;li&gt;enforce message size limits&lt;/li&gt;
&lt;li&gt;store logging records in database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another part of this story is &lt;a href=&#34;https://docs.python.org/2/library/logging.handlers.html#sockethandler&#34;&gt;SocketHandler&lt;/a&gt; which has a feature I&#39;d like
to remove - &lt;a href=&#34;https://docs.python.org/2/library/logging.handlers.html#logging.handlers.SocketHandler.createSocket&#34;&gt;createSocket&lt;/a&gt; method implemets exponential back-off algorithm
which I just don&#39;t need. During my tests intentionally broken (just for tests)
connection to logging service leads to logging records being missed.&lt;/p&gt;
&lt;p&gt;To be clear with the problem. Suppose we have a server and a microservice.
Everything works as expected and is in good shape. Some time later we need to
update the code for logging service and restart it. Using &lt;a href=&#34;https://docs.python.org/2/library/logging.handlers.html#sockethandler&#34;&gt;SocketHandler&lt;/a&gt;
from python&#39;s standard library will force us to restart our microservice
because without this step we will be missing at least one or two logging
records from it (due to the way this handler works).&lt;/p&gt;
&lt;p&gt;I wanted a way to automatically handle such a situation without user
intervention. So, below is a modified version of &lt;a href=&#34;https://docs.python.org/2/library/logging.handlers.html#sockethandler&#34;&gt;SocketHandler&lt;/a&gt;. Every time
it needs to handle a record it will try to connect to logging service to
guarantee message delivery. It uses &lt;a href=&#34;http://stackoverflow.com/a/18189190&#34;&gt;small trick&lt;/a&gt; to detect socket state and
to re-establish connection when needed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

from __future__ import absolute_import

import logging
import socket
import struct
import traceback
try:
    import cPickle as pickle
except ImportError:  # pragma: no cover
    import pickle


class SocketHandler(logging.Handler):
    &amp;quot;&amp;quot;&amp;quot;
    [!] modified version of python&#39;s logging.handlers.SocketHandler

    &amp;quot;&amp;quot;&amp;quot;

    def __init__(self, host, port):
        logging.Handler.__init__(self)
        self.host = host
        self.port = port
        self._sock = None
        self.closeOnError = 1
        self.retry_count = 3

    def makeSocket(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.connect((self.host, self.port))
        except socket.error:
            # TODO sentry
            traceback.print_exc()
            s = None
        else:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        return s

    def _get_sock(self):
        if self._sock is None:
            self._sock = self.makeSocket()
        return self._sock

    def _set_sock(self, value):
        if value is None and self._sock:
            self._sock.close()
        self._sock = value

    sock = property(_get_sock, _set_sock)

    def get_sock_state(self, s):
        # see http://stackoverflow.com/a/18189190
        fmt = &#39;B&#39; * 7 + &#39;I&#39; * 24
        sz = struct.calcsize(fmt)
        x = struct.unpack(
            fmt, s.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, sz))
        return x

    def send(self, s):
        retries = self.retry_count
        while retries &amp;gt; 0:
            sock = self.sock
            retries -= 1
            if sock:
                state = self.get_sock_state(sock)
                # check tcp_info.tcpi_state value is TCP_ESTABLISHED
                if state[0] != 1:
                    self.sock = None
                    continue
                try:
                    if hasattr(sock, &#39;sendall&#39;):
                        sock.sendall(s)
                    else:
                        sentsofar = 0
                        left = len(s)
                        while left &amp;gt; 0:
                            sent = sock.send(s[sentsofar:])
                            sentsofar = sentsofar + sent
                            left = left - sent
                    break
                except socket.error:
                    self.sock = None

    def makePickle(self, record):
        ei = record.exc_info
        if ei:
            dummy = self.format(record)  # noqa
            record.exc_info = None  # to avoid Unpickleable error
        d = dict(record.__dict__)
        d[&#39;msg&#39;] = record.getMessage()
        d[&#39;args&#39;] = None
        s = pickle.dumps(d, pickle.HIGHEST_PROTOCOL)
        if ei:
            record.exc_info = ei  # for next handler
        slen = struct.pack(&#39;&amp;gt;L&#39;, len(s))
        return slen + s

    def handleError(self, record):
        if self.closeOnError and self.sock:
            self.sock = None
        else:
            logging.Handler.handleError(self, record)

    def emit(self, record):
        try:
            s = self.makePickle(record)
            self.send(s)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            # TODO sentry
            traceback.print_exc()
            self.handleError(record)

    def close(self):
        self.acquire()
        try:
            if self.sock:
                self.sock = None
        finally:
            self.release()
        logging.Handler.close(self)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ll put logging service and this handler in production next month. Stay tuned.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>The finger pointing at the moon is not the moon</title>
        <link href="https://ysegorov.github.io/2017/moon/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/moon/</id>
        <updated>2017-03-26T12:51:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;the-finger-pointing-at-the-moon-is-not-the-moon&#34;&gt;The finger pointing at the moon is not the moon &lt;a class=&#34;header-anchor&#34; href=&#34;#the-finger-pointing-at-the-moon-is-not-the-moon&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;14 precepts by &lt;a href=&#34;http://www.seaox.com/thich.html&#34;&gt;&lt;strong&gt;Thich Nhat Hanh&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do not be idolatrous about or bound to any doctrine, theory, or ideology,
even Buddhist ones. All systems of thought are guiding means;
they are not absolute truth.&lt;/p&gt;
&lt;p&gt;Do not think that the knowledge you presently possess is changeless,
absolute truth. Avoid being narrow-minded and bound to present views.
Learn and practice non-attachment from views in order to be open to receive
others&#39; viewpoints. Truth is found in life and not merely in conceptual
knowledge. Be ready to learn throughout our entire life and to observe
reality in yourself and in the world at all times.&lt;/p&gt;
&lt;p&gt;Do not force others, including children, by any means whatsoever, to adopt
your views, whether by authority, threat, money, propaganda, or even
education. However, through compassionate dialogue, help others renounce
fanaticism and narrowness.&lt;/p&gt;
&lt;p&gt;Do not avoid contact with suffering or close your eyes before suffering.
Do not lose awareness of the existence of suffering in the life of the world.
Find ways to be with those who are suffering by all means, including
personal contact and visits, images, sound. By such means, awaken yourself
and others to the reality of suffering in the world.&lt;/p&gt;
&lt;p&gt;Do not accumulate wealth while millions are hungry.
Do not take as the aim of you life fame, profit, wealth, or sensual pleasure.
Live simply and share time, energy, and material resources with those
who are in need.&lt;/p&gt;
&lt;p&gt;Do not maintain anger or hatred. As soon as anger and hatred arise,
practice the meditation on compassion in order to deeply understand
the persons who have caused anger and hatred.
Learn to look at other beings with the eyes of compassion.&lt;/p&gt;
&lt;p&gt;Do not lose yourself in dispersion and in your surroundings.
Learn to practice breathing in order to regain composure of body and mind,
to practice mindfulness, and to develop concentration and understanding.&lt;/p&gt;
&lt;p&gt;Do not utter words that can create discord and cause the community to break.
Make every effort to reconcile and resolve all conflicts, however small.&lt;/p&gt;
&lt;p&gt;Do not say untruthful things for the sake of personal interest or
to impress people. Do not utter words that cause diversion and hatred.
Do not spread news that you do not know to be certain.
Do not criticize or condemn things you are not sure of.
Always speak truthfully and constructively.
Have the courage to speak out about situations of injustice,
even when doing so may threaten your own safety.&lt;/p&gt;
&lt;p&gt;Do not use the Buddhist community for personal gain or profit,
or transform your community into a political party.
A religious community should, however, take a clear stand
against oppression and injustice, and should strive to change
the situation without engaging in partisan conflicts.&lt;/p&gt;
&lt;p&gt;Do not live with a vocation that is harmful to humans and nature.
Do not invest in companies that deprive others of their chance to life.
Select a vocation which helps realize your ideal compassion.&lt;/p&gt;
&lt;p&gt;Do not kill. Do not let others kill.
Find whatever means possible to protect life and to prevent war.&lt;/p&gt;
&lt;p&gt;Possess nothing that should belong to others.
Respect the property of others but prevent others
from enriching themselves from human suffering
or the suffering of other beings.&lt;/p&gt;
&lt;p&gt;Do not mistreat your body.
Learn to handle it with respect.
Do not look on your body as only and instrument.
Preserve vital energies (sexual, breath, spirit) for the realization
of the Way.
Sexual expression should not happen without love and commitment.
In sexual relationships be aware of future suffering that may be caused.
To preserve the happiness of others, respect the rights and commitments
of others.
Be fully aware of the responsibility of bringing new lives into the world.
Meditate on the world into which you are bringing new beings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;No words can replace practice, only practice can make the words&lt;/strong&gt;.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Logger service using epoll - Part 2</title>
        <link href="https://ysegorov.github.io/2017/logger-2/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/logger-2/</id>
        <updated>2017-03-30T16:45:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;logger-service-using-epoll---part-2&#34;&gt;Logger service using epoll - Part 2 &lt;a class=&#34;header-anchor&#34; href=&#34;#logger-service-using-epoll---part-2&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;note&#34;&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; This is a follow-up for &lt;a href=&#34;https://ysegorov.github.io/2017/logger/&#34;&gt;part 1&lt;/a&gt; post about logger service.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So, the task is to have logger service capable of handling, let&#39;s say, 1k
logging records per second. I am expecting about 100 client connections to this
service and It&#39;s clear that it must be stable enough to handle incoming
requests.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Please do remember that all figures in this post I&#39;ve got running the code on
my laptop - YMMV&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To test the service I have this script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time
import random
import logging
import logging.config
import multiprocessing as mp


def setup_logging():
    conf = {
        &#39;version&#39;: 1,
        &#39;disable_existing_loggers&#39;: False,
        &#39;formatters&#39;: {
            &#39;default&#39;: {
                &#39;format&#39;: (
                    &#39;%(levelname)1.1s %(asctime)s %(name)s:%(lineno)3s &#39;
                    &#39;%(message)s&#39;),
                &#39;datefmt&#39;: &#39;%Y.%m.%d %H:%M:%S&#39;,
            }
        },
        &#39;handlers&#39;: {
            &#39;service_logger&#39;: {
                &#39;level&#39;: &#39;DEBUG&#39;,
                # must be importable
                &#39;class&#39;: &#39;svctools.handlers.SocketHandler&#39;,
                &#39;host&#39;: &#39;127.0.0.1&#39;,
                &#39;port&#39;: 5000,
            },
        },
        &#39;loggers&#39;: {
            &#39;&#39;: {
                &#39;level&#39;: &#39;DEBUG&#39;,
                &#39;handlers&#39;: [&#39;service_logger&#39;],
                &#39;propagate&#39;: False,
            },
        },
    }
    logging.config.dictConfig(conf)


def run(idx):
    msg = &#39;[%06d] log message %08d&#39;
    pid = os.getpid()
    logger = logging.getLogger(__name__)
    cnt = count = random.randint(300, 800)
    while True:
        logger.debug(msg, pid, cnt, extra={&#39;trace_id&#39;: idx})
        cnt -= 1
        time.sleep(random.choice((0.01, 0.02, 0.03, 0.04, 0.03, 0.02, 0.01)))
        if cnt == 0:
            break

    logger.debug(&#39;[%06d] --------&#39;, pid, extra={&#39;trace_id&#39;: idx})

    return count


def main():
    pool = mp.Pool(200, setup_logging)
    r = pool.map_async(run, range(1000))

    data = r.get()
    print(&#39;sent %s records&#39; % sum(data))


if __name__ == &amp;quot;__main__&amp;quot;:
    main()

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have pool of 200 processes performing the same action - just calling
&lt;code&gt;logger.debug&lt;/code&gt;.
Single action to be performed by a process is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;randomly select number of logging messages to be send to service (somewhere
between 300 and 800 messages)&lt;/li&gt;
&lt;li&gt;send messages one by one with a tiny delay in between (to simulate some kind
of real load)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will be running 1000 of such actions which means we will send about 500k
messages to our service (this is just an approximation).&lt;/p&gt;
&lt;h3 id=&#34;step-1---logging-to-a-file-only&#34;&gt;Step 1 - logging to a file (only) &lt;a class=&#34;header-anchor&#34; href=&#34;#step-1---logging-to-a-file-only&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was not interesting at all as I&#39;ve got about &lt;strong&gt;8700 records per second&lt;/strong&gt; -
very impressive. But we need all records to be stored in database - to do
a query later. Let&#39;s see.&lt;/p&gt;
&lt;h3 id=&#34;step-2---logging-to-a-file-and-to-postgresql-using-logging-handler&#34;&gt;Step 2 - logging to a file and to PostgreSQL using logging handler &lt;a class=&#34;header-anchor&#34; href=&#34;#step-2---logging-to-a-file-and-to-postgresql-using-logging-handler&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The code for PostgreSQL logging handler is available &lt;a href=&#34;https://gist.github.com/ysegorov/8947d99a016aa00ace51d9ab4d89c428#file-pghandler-py&#34;&gt;here&lt;/a&gt;. This
time results were disappointing - about &lt;strong&gt;200 records per second&lt;/strong&gt; (at the same
time there was no data loss which is good).&lt;/p&gt;
&lt;h3 id=&#34;step-3---logging-to-a-file-and-to-postgresql-using-self-made-handler&#34;&gt;Step 3 - logging to a file and to PostgreSQL using self-made handler &lt;a class=&#34;header-anchor&#34; href=&#34;#step-3---logging-to-a-file-and-to-postgresql-using-self-made-handler&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was clear that our service everytime runs the same query inserting just one
record to database. So, the trick is to employ buffering and to insert records
in bulk using, for example, &lt;a href=&#34;http://initd.org/psycopg/docs/extras.html#psycopg2.extras.execute_values&#34;&gt;&lt;code&gt;psycopg2.extras.execute_values&lt;/code&gt;&lt;/a&gt;.
This time I&#39;ve got about &lt;strong&gt;3600 records per second&lt;/strong&gt; using 1k-blocks - much
better. For a batches of 100 records I&#39;ve got about &lt;strong&gt;3000 records per second&lt;/strong&gt;
which is a bit slower but still good enough.&lt;/p&gt;
&lt;p&gt;This solution has one trick though. As we are prebuffering records there will
be times buffer is not full and there is no incoming records for some time.
This can lead to data loss which is bad. To solve this problem we can use
&lt;a href=&#34;https://docs.python.org/2/library/signal.html#signal.setitimer&#34;&gt;&lt;code&gt;signal.setitimer&lt;/code&gt;&lt;/a&gt; to setup simple timer to send &lt;code&gt;SIGALRM&lt;/code&gt; on a
regular basis and to flush receiving buffer on it.&lt;/p&gt;
&lt;p&gt;Here are the features of the logger service:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no threads or child processes&lt;/li&gt;
&lt;li&gt;edge-triggered epoll for i/o&lt;/li&gt;
&lt;li&gt;PostgreSQL backend&lt;/li&gt;
&lt;li&gt;the code looks ugly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last feature will be fixed soon. Stay tuned.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>WT documentation</title>
        <link href="https://ysegorov.github.io/2017/wt-docs/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/wt-docs/</id>
        <updated>2026-07-26T12:22:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;wt-documentation&#34;&gt;WT documentation &lt;a class=&#34;header-anchor&#34; href=&#34;#wt-documentation&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;strong&gt;Update.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library has been moved to archive, no plans to develop it further&lt;/s&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library was unarchived, rebuilt from scratch and released as 3.0.0 version.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is just a few words about &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; documentation.&lt;/p&gt;
&lt;p&gt;It&#39;s &lt;s&gt;available online&lt;/s&gt; and covers almost all &lt;strong&gt;&lt;code&gt;wt&lt;/code&gt;&lt;/strong&gt; features.&lt;/p&gt;
&lt;p&gt;And it was built using &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt;. Documentation sources are available in
the &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; repository under &lt;code&gt;docs/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;There was &lt;a href=&#34;https://codeberg.org/ysegorov/wt/issues/28&#34;&gt;minor issue&lt;/a&gt; with deployment though.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;The documentation is hosted using &lt;a href=&#34;https://help.github.com/articles/user-organization-and-project-pages/#project-pages&#34;&gt;GitHub pages for projects&lt;/a&gt; and it&#39;s
served under &lt;em&gt;baseurl&lt;/em&gt; (&lt;strong&gt;&lt;code&gt;/wt-docs/&lt;/code&gt;&lt;/strong&gt; in my case)&lt;/s&gt;. I was not aware of this
requirement while developing &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; so internally it&#39;s not supported. This
means there is a difference between local links in &lt;em&gt;development&lt;/em&gt; mode and in
&lt;em&gt;build&lt;/em&gt; mode which can lead to broken local links in &lt;em&gt;build&lt;/em&gt; mode.&lt;/p&gt;
&lt;p&gt;I&#39;ve solved the problem but I&#39;m not sure I like the
solution. There must be a better way to handle &lt;em&gt;baseurl&lt;/em&gt; (this issue was
solved in &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; later).&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Reloadable decorator</title>
        <link href="https://ysegorov.github.io/2017/reloadable/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/reloadable/</id>
        <updated>2026-07-26T12:24:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;reloadable-decorator&#34;&gt;Reloadable decorator &lt;a class=&#34;header-anchor&#34; href=&#34;#reloadable-decorator&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;strong&gt;Update 1.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library has been moved to archive, no plans to develop it further&lt;/s&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2.&lt;/strong&gt; &lt;code&gt;wt&lt;/code&gt; library was unarchived, rebuilt from scratch and released as 3.0.0 version.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; has a feature I&#39;d like to share here. It was one of the first features
of &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; I think.&lt;/p&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem &lt;a class=&#34;header-anchor&#34; href=&#34;#problem&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suppose I have an idea for some post, just like this one.&lt;/p&gt;
&lt;p&gt;I&#39;ve opened terminal, started &lt;strong&gt;wt&lt;/strong&gt; in &lt;em&gt;development&lt;/em&gt; mode using
&lt;strong&gt;&lt;code&gt;wt develop&lt;/code&gt;&lt;/strong&gt; command and started &lt;strong&gt;vim&lt;/strong&gt; for authoring.&lt;/p&gt;
&lt;p&gt;I&#39;m typing for some time...&lt;/p&gt;
&lt;p&gt;Ok, now I&#39;d like to check it in browser and I&#39;m adding some metadata for
this post to configuration - &lt;strong&gt;&lt;code&gt;wt.yaml&lt;/code&gt;&lt;/strong&gt; file.&lt;/p&gt;
&lt;p&gt;After this step I&#39;m expecting refreshed page in the browser to contain updated
data from configuration.&lt;/p&gt;
&lt;h2 id=&#34;solution&#34;&gt;Solution &lt;a class=&#34;header-anchor&#34; href=&#34;#solution&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Internally &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; has a so called &lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/src/wt/engine.py#L40&#34;&gt;engine&lt;/a&gt; to handle
incoming requests. It depends on &lt;strong&gt;&lt;code&gt;wt.yaml&lt;/code&gt;&lt;/strong&gt; configuration and reads it on
initialization.&lt;/p&gt;
&lt;p&gt;It is quite possible for the &lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/src/wt/engine.py#L40&#34;&gt;engine&lt;/a&gt; to contain logic to reload
configuration when needed but I thought this task shouldn&#39;t be implemented
there.&lt;/p&gt;
&lt;p&gt;It would be better to have the possibility to easily turn this feature off when
needed (not while &lt;em&gt;authoring&lt;/em&gt; but while &lt;em&gt;developing&lt;/em&gt; the library) or even just
throw away.&lt;/p&gt;
&lt;p&gt;So, here comes &lt;strong&gt;reloadable&lt;/strong&gt; decorator:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

import logging
import os


class reloadable(object):

    def __init__(self, message):
        self._message = message
        self._values = {}
        self._lastmods = {}
        self.logger = logging.getLogger(&#39;wt.reloadable&#39;)

    def __call__(self, fn):

        def inner(filename):
            v = self._values.get(filename)
            m = self._lastmods.get(filename)
            try:
                modified = os.stat(filename).st_mtime
            except FileNotFoundError:
                self.logger.warn(
                    &#39;File not found &amp;quot;%s&amp;quot;, skipping stat&#39;, filename)
                pass
            else:
                if m is None or modified &amp;gt; m:
                    self.logger.debug(
                        &#39;File &amp;quot;%s&amp;quot; modified, %s&#39;, filename, self._message)
                    self._lastmods[filename] = modified
                    v = None

            if v is None:
                self._values[filename] = v = fn(filename)
            return v
        return inner
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It keeps last modified times for files and caches results of function calls. In
case file was modified cached value will be automatically updated. Pretty
simple yet very useful.&lt;/p&gt;
&lt;p&gt;Real life usage example looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

from .decorators import reloadable
from .engine import WT


@reloadable(&#39;(re)loading configuration...&#39;)
def engine(fn):
    return WT(fn)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Currently &lt;a href=&#34;https://codeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; uses &lt;a href=&#34;http://aiohttp.readthedocs.io/en/stable/&#34;&gt;aiohttp&lt;/a&gt; as http backend.&lt;/p&gt;
&lt;p&gt;It&#39;s only configured handler calls &lt;strong&gt;&lt;code&gt;engine&lt;/code&gt;&lt;/strong&gt; function to get rendering
&lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/src/wt/engine.py#L40&#34;&gt;engine&lt;/a&gt; instance (you can check &lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/src/wt/server.py&#34;&gt;server module&lt;/a&gt; sources
for details).&lt;/p&gt;
&lt;p&gt;In case configuration file was updated this call will create new fresh instance
of &lt;a href=&#34;https://codeberg.org/ysegorov/wt/src/branch/main/src/wt/engine.py#L40&#34;&gt;engine&lt;/a&gt; ready to render pages and posts.
This instance will be cached within &lt;strong&gt;reloadable&lt;/strong&gt; decorator cache so any
subsequent calls to &lt;strong&gt;&lt;code&gt;engine&lt;/code&gt;&lt;/strong&gt; function will just have the very same
instance in return (till configuration was updated again).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;That&#39;s it for &lt;strong&gt;reloadable&lt;/strong&gt; decorator. Stay tuned.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Dotenv</title>
        <link href="https://ysegorov.github.io/2017/dotenv/" rel="alternate" />
        <id>https://ysegorov.github.io/2017/dotenv/</id>
        <updated>2017-04-13T16:40:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;dotenv&#34;&gt;Dotenv &lt;a class=&#34;header-anchor&#34; href=&#34;#dotenv&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I&#39;ve got used to &lt;a href=&#34;https://github.com/theskumar/python-dotenv&#34;&gt;python-dotenv&lt;/a&gt; library to customize some
project&#39;s settings on per-deployment basis. But there is one thing which I
can&#39;t say I like.&lt;/p&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem &lt;a class=&#34;header-anchor&#34; href=&#34;#problem&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The problem is the way this library makes values from &lt;code&gt;.env&lt;/code&gt; available to
project - by using &lt;code&gt;os.environ.setdefault&lt;/code&gt; which actually pollutes project&#39;s
environment.&lt;/p&gt;
&lt;p&gt;By occasion this can lead to some sensitive information like api keys to leak.
Let&#39;s fix it.&lt;/p&gt;
&lt;h2 id=&#34;solution&#34;&gt;Solution &lt;a class=&#34;header-anchor&#34; href=&#34;#solution&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My first attempt was to check the library&#39;s API and find a way to load values
without polluting &lt;code&gt;os.environ&lt;/code&gt;. This is possible and here is the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

import os

from dotenv.main import dotenv_values

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DOTFILE = os.environ.get(&#39;DOTFILE&#39;, &#39;.env&#39;)

dotenv = {}
dotenv_path = os.path.join(BASE_DIR, DOTFILE)
if os.path.isfile(dotenv_path):
    dotenv = dotenv_values(dotenv_path)

def env(key, default=None):
    return os.environ.get(key, dotenv.get(key, default))

API_KEY = env(&#39;API_KEY&#39;, &#39;test-key&#39;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This solution works and looks pretty, well, reasonable. At the same time
&lt;code&gt;dotenv_values&lt;/code&gt; function is not documented and there is a chance API can be
changed.&lt;/p&gt;
&lt;p&gt;Besides &lt;a href=&#34;https://github.com/theskumar/python-dotenv&#34;&gt;python-dotenv&lt;/a&gt; has features I don&#39;t need, like
command-line interface or automatic &lt;code&gt;.env&lt;/code&gt; file location up the directory tree
(I always know where &lt;code&gt;.env&lt;/code&gt; file should be).&lt;/p&gt;
&lt;p&gt;So, I&#39;ve rolled my own solution which has fewer lines of code and is very easy
to reason about:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

from __future__ import absolute_import

import os
import codecs
import logging


logger = logging.getLogger(__name__)


def load_dotenv(filename, encoding=&#39;utf-8&#39;):

    decoder = codecs.getdecoder(&#39;unicode_escape&#39;)

    def decode(v):
        if v and v[0] == v[-1] and v[0] in (&#39;&amp;quot;&#39;, &#39;\&#39;&#39;):
            v = decoder(v[1:-1])[0]
        return v

    with codecs.open(filename, &#39;rb&#39;, encoding=encoding) as f:
        lines = (x.strip() for x in f if x.strip())
        lines = (x for x in lines if not x.startswith(&#39;#&#39;) and &#39;=&#39; in x)
        lines = (x.split(&#39;=&#39;, 1) for x in lines)
        lines = ((x.strip(), y.strip()) for x, y in lines)
        lines = ((x.upper(), decode(y)) for x, y in lines)
        for line in lines:
            yield line


class dotenv(object):

    def __init__(self, filename=&#39;.env&#39;, encoding=&#39;utf-8&#39;):
        fn = filename
        if not os.path.isabs(filename):
            filename = os.path.abspath(os.path.join(os.curdir, filename))
        if not os.path.exists(filename):
            logger.warning(&#39;dotenv file &amp;quot;%s&amp;quot; not found&#39;, fn)
            filename = None
        self.filename = filename
        self.encoding = encoding
        self._data = None

    @property
    def data(self):
        if self._data is None and self.filename is not None:
            self._data = dict(
                load_dotenv(self.filename, encoding=self.encoding))
        return self._data

    def get(self, key, default=None):
        data = self.data or {}
        return os.environ.get(key, data.get(key, default))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can be used like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# -*- coding: utf-8 -*-

import os

from .dotenv import dotenv

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DOTFILE = os.environ.get(&#39;DOTFILE&#39;, &#39;.env&#39;)

env = dotenv(filename=os.path.join(BASE_DIR, DOTFILE))

API_KEY = env.get(&#39;API_KEY&#39;, &#39;test-key&#39;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is very easy to extend &lt;code&gt;dotenv&lt;/code&gt; class with methods like &lt;code&gt;get_bool&lt;/code&gt;,
&lt;code&gt;get_int&lt;/code&gt;, &lt;code&gt;get_list&lt;/code&gt; or whatever you need and provide some logic to verify
settings values as needed.&lt;/p&gt;
&lt;p&gt;Value coming from &lt;code&gt;os.environ&lt;/code&gt; takes precedence over &lt;code&gt;.env&lt;/code&gt; value when
specified (this is useful while running &lt;em&gt;jenkins&lt;/em&gt; jobs).&lt;/p&gt;
&lt;p&gt;By implementing self-made solution we can simplify
our project&#39;s dependency tree and be sure everything works as we need.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;That&#39;s it for &lt;strong&gt;dotenv&lt;/strong&gt;. Stay tuned.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>AU6601 PCI-E Flash card reader and Linux kernel 4.16</title>
        <link href="https://ysegorov.github.io/2018/au6601-2/" rel="alternate" />
        <id>https://ysegorov.github.io/2018/au6601-2/</id>
        <updated>2018-05-05T07:12:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;alcor-micro-au6601-pci-e-flash-card-reader-controller-and-linux-kernel-416&#34;&gt;Alcor Micro AU6601 PCI-E Flash card reader controller and Linux kernel 4.16 &lt;a class=&#34;header-anchor&#34; href=&#34;#alcor-micro-au6601-pci-e-flash-card-reader-controller-and-linux-kernel-416&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I&#39;ve got email from &lt;em&gt;Justin Faber&lt;/em&gt; today saying the procedure, described
&lt;a href=&#34;https://ysegorov.github.io/2016/au6601/&#34;&gt;here&lt;/a&gt;, doesn&#39;t work for Linux kernel 4.16.6-1 in ArchLinux - build
fails with the following log:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;make -C /lib/modules/4.16.6-1-ARCH/build/ SUBDIRS=/var/lib/dkms/au6601/0.3/build modules
make[1]: warning: jobserver unavailable: using -j1.  Add &#39;+&#39; to parent make rule.
make[1]: Entering directory &#39;/usr/lib/modules/4.16.6-1-ARCH/build&#39;
  CC [M]  /var/lib/dkms/au6601/0.3/build/au6601.o
/var/lib/dkms/au6601/0.3/build/au6601.c: In function ‘au6601_pci_probe’:
/var/lib/dkms/au6601/0.3/build/au6601.c:1187:2: error: implicit declaration of function ‘setup_timer’; did you mean ‘setup_irq’? [-Werror=implicit-function-declaration]
  setup_timer(&amp;amp;host-&amp;gt;timer, au6601_timeout_timer, (unsigned long)host);
  ^~~~~~~~~~~
  setup_irq
/var/lib/dkms/au6601/0.3/build/au6601.c: In function ‘au6601_send_cmd’:
/var/lib/dkms/au6601/0.3/build/au6601.c:619:5: warning: ‘ctrl’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  u8 ctrl; /* some mysterious flags and control */
     ^~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:325: /var/lib/dkms/au6601/0.3/build/au6601.o] Error 1
make[1]: *** [Makefile:1562: _module_/var/lib/dkms/au6601/0.3/build] Error 2
make[1]: Leaving directory &#39;/usr/lib/modules/4.16.6-1-ARCH/build&#39;
make: *** [Makefile:33: default] Error 2

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://duckduckgo.com/&#34;&gt;DuckDuckGo&lt;/a&gt; (my default search engine, by the way) &lt;a href=&#34;https://duckduckgo.com/?q=linux+setup_timer+timer_setup+site%3Agithub.com&#34;&gt;helped&lt;/a&gt;
to localize &lt;a href=&#34;https://github.com/torvalds/linux/commit/e99e88a9d2b067465adaa9c111ada99a041bef9a&#34;&gt;the issue&lt;/a&gt; - changes in Linux kernel timers API.&lt;/p&gt;
&lt;p&gt;I&#39;ve followed instructions from the &lt;a href=&#34;https://github.com/torvalds/linux/commit/e99e88a9d2b067465adaa9c111ada99a041bef9a&#34;&gt;commit comments&lt;/a&gt;
and prepared the &lt;em&gt;patch&lt;/em&gt; and &lt;em&gt;PKGBUILD&lt;/em&gt; to simplify installation:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/ysegorov/951ae99426f5bd9092c3b4138e207af2.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;&lt;strong&gt;Please use this procedure and generated package at your own risk as I&#39;m not
a Linux kernel driver developer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here is an updated version of steps to install the driver for &lt;strong&gt;amd64&lt;/strong&gt;
architecture and Linux kernel 4.16+:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create temporary directory somewhere and &lt;code&gt;cd&lt;/code&gt; into it&lt;/li&gt;
&lt;li&gt;download &lt;a href=&#34;https://gist.github.com/ysegorov/951ae99426f5bd9092c3b4138e207af2&#34;&gt;patch and PKGBUILD&lt;/a&gt; (ensure &lt;code&gt;PKGBUILD&lt;/code&gt; and
&lt;code&gt;au6601-timers.diff&lt;/code&gt; are located in the root of previously created
temporary directory)&lt;/li&gt;
&lt;li&gt;build and install package using &lt;code&gt;makepkg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;install kernel driver&lt;/li&gt;
&lt;li&gt;use card reader :)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;
$ mkdir au6601-dkms &amp;amp;&amp;amp; cd au6601-dkms
$ wget -O au6601-pkgbuild.zip https://gist.github.com/ysegorov/951ae99426f5bd9092c3b4138e207af2/archive/master.zip
$ unzip -j au6601-pkgbuild.zip
$ makepkg -si
$ sudo modprobe au6601-pci
$ udevil mount /dev/mmcblk0p1

# profit!

&lt;/code&gt;&lt;/pre&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Wireguard and Linux network namespaces - perfect fit</title>
        <link href="https://ysegorov.github.io/2020/wireguard/" rel="alternate" />
        <id>https://ysegorov.github.io/2020/wireguard/</id>
        <updated>2020-04-22T17:35:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;wireguard-and-linux-network-namespaces---perfect-fit&#34;&gt;Wireguard and Linux network namespaces - perfect fit &lt;a class=&#34;header-anchor&#34; href=&#34;#wireguard-and-linux-network-namespaces---perfect-fit&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I&#39;m using two browsers usually - Firefox (switched to IceCat recently) and
Chromium.&lt;/p&gt;
&lt;p&gt;Firefox/IceCat is my workhorse, which is configured to route all
traffic through SOCKS5 proxy (&lt;a href=&#34;https://www.linode.com&#34;&gt;Linode&lt;/a&gt; instance actually).&lt;/p&gt;
&lt;p&gt;I would definitely stay solely with it but some sites don&#39;t like requests
coming from VPS servers so I have to use Chromium for such cases (and it always
run in private mode to keep it clean).&lt;/p&gt;
&lt;p&gt;SOCKS5 proxy works pretty good for me but I was curious if it&#39;s possible to
use &lt;a href=&#34;https://www.wireguard.com&#34;&gt;wireguard&lt;/a&gt; for my usecase - to route Firefox/IceCat traffic
through VPN keeping all other traffic as is.&lt;/p&gt;
&lt;p&gt;For domain name resolution I&#39;m using locally installed &lt;a href=&#34;https://nlnetlabs.nl/projects/unbound/about/&#34;&gt;Unbound&lt;/a&gt;
server which is bound to localhost. My &lt;code&gt;/etc/resolv.conf&lt;/code&gt; file looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nameserver 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is configured to forward requests to &lt;a href=&#34;https://www.quad9.net&#34;&gt;Quad9&lt;/a&gt; resolver (no Google, no
Cloudflare, right) but I&#39;m planning to turn forwarding off and just use
&lt;a href=&#34;https://nlnetlabs.nl/projects/unbound/about/&#34;&gt;Unbound&lt;/a&gt; on its own.&lt;/p&gt;
&lt;p&gt;There are numerous posts in the Internet covering &lt;a href=&#34;https://www.wireguard.com&#34;&gt;wireguard&lt;/a&gt;
configuration so I&#39;ll just show my server/client configuration with some notes.&lt;/p&gt;
&lt;p&gt;For some reason I&#39;ve missed the fact that &lt;code&gt;wg-quick&lt;/code&gt; helper uses advanced
version of &lt;code&gt;wg&lt;/code&gt; configuration file syntax which means &lt;code&gt;wg-quick&lt;/code&gt; configuration
file can&#39;t be used with &lt;code&gt;wg&lt;/code&gt;. I&#39;ve lost some time while battling this issue.&lt;/p&gt;
&lt;p&gt;Summary of the settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;10.10.10.0/24&lt;/code&gt; - VPN network&lt;/li&gt;
&lt;li&gt;&lt;code&gt;10.10.10.1/32&lt;/code&gt; - VPN server address&lt;/li&gt;
&lt;li&gt;&lt;code&gt;10.10.10.10/32&lt;/code&gt; - VPN client address&lt;/li&gt;
&lt;li&gt;&lt;code&gt;55000&lt;/code&gt; - VPN server port wireguard will be listening on&lt;/li&gt;
&lt;li&gt;VPN server will route all traffic coming from client to the outside world&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;server&#34;&gt;Server &lt;a class=&#34;header-anchor&#34; href=&#34;#server&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My server configuration file looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;# /etc/wireguard/wg0.conf on the server

[Interface]
PrivateKey = &amp;lt;private key of the server&amp;gt;
ListenPort = 55000

[Peer]
PublicKey = &amp;lt;public key of the client&amp;gt;
PresharedKey = &amp;lt;preshared key&amp;gt;
AllowedIPs = 10.10.10.10/32
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use &lt;a href=&#34;https://www.alpinelinux.org&#34;&gt;Alpine Linux&lt;/a&gt; on the server for my experiments with wireguard
and my &lt;code&gt;wg0&lt;/code&gt; interface is defined like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# excerpt from /etc/network/interfaces

auto wg0
iface wg0 inet static
  address 10.10.10.1
  netmask 255.255.255.0
  pre-up ip link add dev wg0 type wireguard
  pre-up wg setconf wg0 /etc/wireguard/wg0.conf
  pre-down ip link delete dev wg0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One more player here is firewall (&lt;code&gt;iptables&lt;/code&gt; in my case). It must be configured
to allow traffic coming from &lt;code&gt;wg0&lt;/code&gt; interface to be forwarded to outside world.&lt;/p&gt;
&lt;p&gt;Something like this should help you to get started:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sudo iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT
$ sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.10.10.0/24 -j MASQUERADE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&#39;t forget to make these rules permanent and allow forwarding on the server
using &lt;code&gt;sysctl&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;net.ipv4.ip_forward=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it for the server.&lt;/p&gt;
&lt;h2 id=&#34;client&#34;&gt;Client &lt;a class=&#34;header-anchor&#34; href=&#34;#client&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Client configuration file looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;# /etc/wireguard/wg0.conf on the client

[Interface]
PrivateKey = &amp;lt;private key of the client&amp;gt;

[Peer]
PublicKey = &amp;lt;public key of the server&amp;gt;
PresharedKey = &amp;lt;preshared key&amp;gt;
Endpoint = &amp;lt;server public ip&amp;gt;:55000
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ve faced another issue while configuring the client - something absolutely
unexpected when pinging any host, even VPN server endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ ping 10.10.10.1
PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.
From 10.10.10.10 icmp_seq=1 Destination Host Unreachable
ping: sendmsg: Required key not available
From 10.10.10.10 icmp_seq=2 Destination Host Unreachable
ping: sendmsg: Required key not available
From 10.10.10.10 icmp_seq=3 Destination Host Unreachable
ping: sendmsg: Required key not available
^C
--- 10.10.10.1 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2028ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same for pinging Google DNS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
From 10.10.10.10 icmp_seq=1 Destination Host Unreachable
ping: sendmsg: Required key not available
From 10.10.10.10 icmp_seq=2 Destination Host Unreachable
ping: sendmsg: Required key not available
From 10.10.10.10 icmp_seq=3 Destination Host Unreachable
ping: sendmsg: Required key not available
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2037ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason for this was &lt;code&gt;AllowedIPs&lt;/code&gt; misconfiguration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;# This is wrong setting
AllowedIPs = 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ve somehow lost CIDR part from the address which means address will look like
&lt;code&gt;0.0.0.0/32&lt;/code&gt; which is absolutely wrong.&lt;/p&gt;
&lt;p&gt;Pay attention to &lt;code&gt;wg&lt;/code&gt; output, to &lt;code&gt;allowed ips&lt;/code&gt; value especially:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sudo wg
interface: wg0
  public key: &amp;lt;client public key&amp;gt;
  private key: (hidden)
  listening port: 52312

peer: &amp;lt;server public key&amp;gt;
  preshared key: (hidden)
  endpoint: &amp;lt;server ip address&amp;gt;:55000
  allowed ips: 0.0.0.0/32
  latest handshake: 1 minute, 12 seconds ago
  transfer: 644 B received, 2.23 KiB sent
  persistent keepalive: every 25 seconds
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, correct value for &lt;code&gt;AllowedIPs&lt;/code&gt; should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;# This is correct setting
AllowedIPs = 0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now we&#39;ve come to the most interesting part of the show - to client-side
network configuration.&lt;/p&gt;
&lt;p&gt;The solution for my usecase was &lt;a href=&#34;https://www.wireguard.com/netns/#sample-script&#34;&gt;here&lt;/a&gt; - simple
script by (probably) &lt;a href=&#34;https://www.wireguard.com&#34;&gt;wireguard&lt;/a&gt; author. Thank you, Jason!&lt;/p&gt;
&lt;p&gt;After some experiments I&#39;ve taken an opposite approach from the original -
prepared &lt;code&gt;wg0&lt;/code&gt; interface is moved to &lt;code&gt;vpn&lt;/code&gt; namespace and is configured to be
the default route within this namespace.&lt;/p&gt;
&lt;p&gt;We can check what interfaces our new &lt;code&gt;vpn&lt;/code&gt; namespace has and how routing table
looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ vpn up
...
$ vpn exec ip link
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
10: wg0: &amp;lt;POINTOPOINT,NOARP,UP,LOWER_UP&amp;gt; mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/none
...
$ vpn exec ip route
default dev wg0 scope link
10.10.10.0/24 dev wg0 proto kernel scope link src 10.10.10.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty good, right?&lt;/p&gt;
&lt;p&gt;One more minor issue was the lack of domain name resolution for programs
running within &lt;code&gt;vpn&lt;/code&gt; namespace. I was not expecting this so it took some time
to understand the reason.&lt;/p&gt;
&lt;p&gt;Citing &lt;a href=&#34;http://manpages.ubuntu.com/manpages/trusty/man8/ip-netns.8.html&#34;&gt;ip-netns&lt;/a&gt; manual:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A network namespace is logically another copy of the network stack, with
its own routes, firewall rules, and network devices.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means nobody is listening on &lt;code&gt;127.0.0.1:53&lt;/code&gt; within &lt;code&gt;vpn&lt;/code&gt; namespace. We can
easily solve this issue by starting another copy of &lt;a href=&#34;https://nlnetlabs.nl/projects/unbound/about/&#34;&gt;unbound&lt;/a&gt; within
&lt;code&gt;vpn&lt;/code&gt; namespace (I&#39;ve decided to use separate copy of &lt;code&gt;unbound.conf&lt;/code&gt; for this
named &lt;code&gt;unbound.vpn.conf&lt;/code&gt;, YMMV).&lt;/p&gt;
&lt;p&gt;Here is the script I&#39;m using to manage VPN:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/usr/bin/env bash

set -ex

[[ $UID != 0 ]] &amp;amp;&amp;amp; exec sudo -E &amp;quot;$(readlink -f &amp;quot;$0&amp;quot;)&amp;quot; &amp;quot;$@&amp;quot;

NS=&amp;quot;vpn&amp;quot;
WGIF=&amp;quot;wg0&amp;quot;
WGCONF=&amp;quot;/etc/wireguard/$WGIF.conf&amp;quot;
WGADDRIPV4=&amp;quot;10.10.10.10/24&amp;quot;
UNBOUNDCONF=&amp;quot;/etc/unbound/unbound.$NS.conf&amp;quot;
UNBOUNDPID=&amp;quot;/run/unbound.$NS.pid&amp;quot;

up() {
    ip netns add $NS
    ip link add $WGIF type wireguard
    wg setconf $WGIF $WGCONF
    ip link set $WGIF netns $NS
    ip -n $NS addr add $WGADDRIPV4 dev $WGIF
    ip -n $NS link set lo up
    ip -n $NS link set $WGIF up
    ip -n $NS route add default dev $WGIF
    ip netns exec $NS unbound -c $UNBOUNDCONF
}

down() {
    UPID=`cat $UNBOUNDPID`
    kill $UPID || true
    ip -n $NS link set $WGIF down
    ip -n $NS link del $WGIF
    ip netns del $NS
}

status() {
    exec ip netns exec $NS wg
}

execi() {
    exec ip netns exec $NS sudo -E -u \#${SUDO_UID:-$(id -u)} -g \#${SUDO_GID:-$(id -g)} -- &amp;quot;$@&amp;quot;
}

command=&amp;quot;$1&amp;quot;
shift

case &amp;quot;$command&amp;quot; in
    up) up &amp;quot;$@&amp;quot; ;;
    down) down &amp;quot;$@&amp;quot; ;;
    exec) execi &amp;quot;$@&amp;quot; ;;
    status) status &amp;quot;$@&amp;quot; ;;
    *) echo &amp;quot;Usage: $0 up|down|exec&amp;quot; &amp;gt;&amp;amp;2; exit 1 ;;
esac
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can start Firefox/IceCat within &lt;code&gt;vpn&lt;/code&gt; namespace and be sure all traffic
is routed through VPN:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ vpn exec icecat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m using &lt;code&gt;netctl&lt;/code&gt; to manage my network interfaces and the plan is to use
&lt;a href=&#34;https://wiki.archlinux.org/index.php/Netctl#Using_hooks&#34;&gt;netctl hooks&lt;/a&gt; to bring VPN interface up or down as needed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.wireguard.com&#34;&gt;wireguard&lt;/a&gt; looks quite good (one more time - thank you, Jason A.
Donenfeld!) and I&#39;m planning to use it for some time to decide if I can switch
from SOCKS5 proxy to VPN.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Zola</title>
        <link href="https://ysegorov.github.io/2020/zola/" rel="alternate" />
        <id>https://ysegorov.github.io/2020/zola/</id>
        <updated>2026-07-26T12:23:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;zola&#34;&gt;Zola &lt;a class=&#34;header-anchor&#34; href=&#34;#zola&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;markdown-alert markdown-alert-note&#34;&gt;
&lt;p class=&#34;markdown-alert-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update.&lt;/strong&gt; I&#39;ve decided to switch back to &lt;code&gt;wt&lt;/code&gt;. It was rebuilt from scratch and
released as 3.0.0 version.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I&#39;ve decided to switch from &lt;a href=&#34;https://odeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt; (which is archived now) to &lt;a href=&#34;https://www.getzola.org/&#34;&gt;zola&lt;/a&gt; to
manage this blog.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wt&lt;/code&gt; worked quite well for me but it requires time to manage it and to
develop it further (and I was not happy with &lt;code&gt;yaml&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;There are a lot of alternatives in this area and by occasion I&#39;ve met
&lt;a href=&#34;https://www.getzola.org/&#34;&gt;zola&lt;/a&gt;. Luckily, it has most of the features I was using with &lt;a href=&#34;https://odeberg.org/ysegorov/wt/&#34;&gt;wt&lt;/a&gt;
(actually, it was the reason to switch to &lt;code&gt;zola&lt;/code&gt; and to archive &lt;code&gt;wt&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;It took some time to understand the way &lt;a href=&#34;https://www.getzola.org/&#34;&gt;zola&lt;/a&gt; works - mostly to convert
templates from &lt;a href=&#34;https://jinja.palletsprojects.com/&#34;&gt;jinja&lt;/a&gt; to &lt;a href=&#34;https://tera.netlify.app/&#34;&gt;tera&lt;/a&gt; and to update front-matter
from &lt;a href=&#34;https://yaml.org&#34;&gt;yaml&lt;/a&gt; to &lt;a href=&#34;https://toml.io&#34;&gt;toml&lt;/a&gt; format within markdown files.&lt;/p&gt;
&lt;p&gt;I was hit by just one issue while converting this blog from &lt;code&gt;wt&lt;/code&gt; to &lt;code&gt;zola&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It was not clear to me that there is no need to apply &lt;code&gt;markdown&lt;/code&gt; filter to
content in templates as it was applied implicitly. Applying it for a second
time breaks syntax highlighting formatting which led me to a thought that I
can&#39;t use &lt;code&gt;zola&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Happily, I&#39;ve looked through the &lt;code&gt;zola&#39;s&lt;/code&gt; issues and found &lt;a href=&#34;https://github.com/getzola/zola/issues/989&#34;&gt;this
one&lt;/a&gt;. There is no need to apply &lt;code&gt;markdown&lt;/code&gt; filter to
content in templates. Yay. Perfect.&lt;/p&gt;
&lt;p&gt;Let&#39;s see how it will work for me.&lt;/p&gt;
&lt;p&gt;Stay tuned and take care of you and your family.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    <entry>
        <title>Markdown preview (Rust version)</title>
        <link href="https://ysegorov.github.io/2020/mdpreview/" rel="alternate" />
        <id>https://ysegorov.github.io/2020/mdpreview/</id>
        <updated>2020-05-05T07:38:00+00:00</updated>
        <summary></summary>
        <content type="html">
            &lt;h1 id=&#34;markdown-preview-written-in-rust&#34;&gt;Markdown preview written in Rust &lt;a class=&#34;header-anchor&#34; href=&#34;#markdown-preview-written-in-rust&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;About a year or so ago I&#39;ve switched to self-made python script to preview
markdown file in browser (&lt;a href=&#34;https://github.com/ysegorov/dotfiles/commit/3e54334f3afbb2f79b1536661ac5c7e469228d51#diff-222c971ff832264e6f73fa6475e6ffeb&#34;&gt;this commit&lt;/a&gt; introduced it in my
own &lt;a href=&#34;https://github.com/ysegorov/dotfiles&#34;&gt;dotfiles&lt;/a&gt; repository).&lt;/p&gt;
&lt;p&gt;It was using &lt;a href=&#34;https://pandoc.org&#34;&gt;pandoc&lt;/a&gt; under the hood to convert markdown to html. Well,
it was not optimal, probably, but it worked.&lt;/p&gt;
&lt;p&gt;I&#39;ve started to read &lt;a href=&#34;https://www.rust-lang.org&#34;&gt;Rust&lt;/a&gt; documentation recently and decided to
(re)implement markdown preview in Rust.&lt;/p&gt;
&lt;p&gt;The most valuable thing I saw in this was the fact that it will be single
binary to use - no third-party dependencies would be needed to install.&lt;/p&gt;
&lt;p&gt;So, here is &lt;a href=&#34;https://github.com/ysegorov/mdpreview-rs&#34;&gt;the code&lt;/a&gt; - markdown preview written in Rust.&lt;/p&gt;
&lt;p&gt;This is my first project written in Rust and it is definitely not as idiomatic
as it should be and has no tests at the moment but it works as expected. Yay.&lt;/p&gt;
&lt;p&gt;Under the hood &lt;a href=&#34;https://github.com/ysegorov/mdpreview-rs&#34;&gt;mdpreview&lt;/a&gt; uses following Rust libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.rs/clap/&#34;&gt;clap&lt;/a&gt; - to process command-line arguments,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.rs/pulldown-cmark/&#34;&gt;pulldown-cmark&lt;/a&gt; - to convert markdown to html,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.rs/hyper/&#34;&gt;hyper&lt;/a&gt; and &lt;a href=&#34;https://docs.rs/tokio/&#34;&gt;tokio&lt;/a&gt; - web server to serve generated html.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some ideas for the code I&#39;ve got looking through sources of &lt;a href=&#34;https://www.getzola.org&#34;&gt;zola&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html&#34;&gt;Ownership&lt;/a&gt; is a new concept to me and I&#39;m still not sure I&#39;m
getting it right but Rust is definitely worth trying. Here is the list of
resources I&#39;m using to study Rust (just for the record):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.rust-lang.org/book/&#34;&gt;The Book&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.rust-lang.org/stable/rust-by-example/&#34;&gt;Rust By Example&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://rust-lang-nursery.github.io/rust-cookbook/intro.html&#34;&gt;Rust Cookbook&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.rust-lang.org/std/index.html&#34;&gt;The Standard Library&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://crates.io&#34;&gt;crates.io&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.rs&#34;&gt;docs.rs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&#39;s it for the &lt;a href=&#34;https://github.com/ysegorov/mdpreview-rs&#34;&gt;mdpreview&lt;/a&gt; intro, let&#39;s move on and
(re)implement in Rust something else. Stay tuned.&lt;/p&gt;

        </content>
        <author>
            <name>Yuri Egorov</name>
        </author>
    </entry>
    
</feed>