<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Zhihao Lou's Notebook</title>
    <description>Welcome to Zhihao Lou's Notebook. Here you can find my notes about things I'm learning.
</description>
    <link>http://zhlou.github.io/</link>
    <atom:link href="http://zhlou.github.io/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 01 Mar 2024 02:53:35 +0000</pubDate>
    <lastBuildDate>Fri, 01 Mar 2024 02:53:35 +0000</lastBuildDate>
    <generator>Jekyll v3.9.5</generator>
    
      <item>
        <title>How to Reverse Proxy Jupyter Notebook on a Subpath Using Nginx</title>
        <description>&lt;p&gt;Recently, I needed to proxy my Jupyter Notebook web interface from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host.domain:8888&lt;/code&gt; to a subpath directly from the HTTP 80 port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host.domain/jupyter/&lt;/code&gt;. Unfortunately, the fact that Jupyter uses WebSocket for the communication between its kernel and the web application, makes setting up correct proxy in Nginx slightly more complicated. After a few searches and experimentation, I have reached a working solution, which I am documenting below.&lt;/p&gt;

&lt;h4 id=&quot;in-jupyter_notebook_configpy-file&quot;&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jupyter_notebook_config.py&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;In order for the Jupyter server to serve files correctly, we need to set its base URL in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME/.jupyter/jupyter_notebook_config.py&lt;/code&gt;. Simply set or add the following line&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ServerApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'/jupyter/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;in-http-section-of-nginxconf-file&quot;&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; section of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;We need to create a variable based on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$http_upgrade&lt;/code&gt; value&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;in-server-section-of-nginxconf-file&quot;&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server&lt;/code&gt; section of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;We need to define a subpath and use the variable we just defined&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;location /jupyter/ {
        proxy_pass http://localhost:8888;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header Connection $connection_upgrade;
	proxy_set_header Upgrade $http_upgrade;
}
&lt;/code&gt;&lt;/pre&gt;
</description>
        <pubDate>Thu, 29 Feb 2024 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2024-02-29/reverse-proxy-jupyter-on-sub-path/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2024-02-29/reverse-proxy-jupyter-on-sub-path/</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Linux Server Review: Fedora 37 Server Edition</title>
        <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;/2023-01-05/linux-server-review-debian-11/&quot;&gt;previous post&lt;/a&gt;, we’ve reviewed Debian 11 from the perspective of using it as a server. Today, let’s check out the other major distribution, Fedora 37 Server Edition.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The installation is done using net install image. Fedora installation process really encourages you to use its graphical interface, and its TUI has very limited capability. Compare to Debian, it is a much heavier weight experience. The installation process needs at least 2GB of RAM to succeed. Even in TUI, the process will crash if has only 1GB of memory.&lt;/p&gt;

&lt;p&gt;On the other hand, the Fedora’s installer (the older but lesser known &lt;a href=&quot;https://anaconda-installer.readthedocs.io/en/latest/&quot;&gt;Anaconda&lt;/a&gt;) allows much more flexibility and customization than Debian’s installation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/fedora_install_custom_root_setting.png&quot; alt=&quot;Fedora Install Root Account&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In particular, you can fully control the enable / disable of root account, whether allowing SSH as root using password, and regular user account’s group setting all independently.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/fedora_install_user_creation.png&quot; alt=&quot;Fedora Install User Account&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;default-service-and-security&quot;&gt;Default Service and Security&lt;/h2&gt;
&lt;p&gt;Fedora 37 Server Edition by defaults installs &lt;a href=&quot;https://cockpit-project.org/&quot;&gt;Cockpit&lt;/a&gt; that runs on port 9090. This is a fully featured server management web service (web console, in Red Hat’s documentation) that make lots of system administration work straightforward. It also contain lots of additional capabilities like managing virtual machines or containers. But those features are not limited to Fedora, and beyond the scope of this review.&lt;/p&gt;

&lt;p&gt;From security point of view, the default settings for Fedora Server is really tight. It has only port 22 (SSH) and 9090 (aforementioned Cockpit) open out of the box. More importantly, the majority ports are configured to drop the packet outright. That makes port scanning takes more than 10x longer than using reject.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Nmap 7.93 scan initiated Mon Jan  9 22:35:45 2023 as: nmap -p- -T4 -oN - 192.168.1.55
Nmap scan report for fedora-server.lan (192.168.1.55)
Host is up (0.00059s latency).
Not shown: 65383 filtered tcp ports (no-response), 150 filtered tcp ports (admin-prohibited)
PORT     STATE SERVICE
22/tcp   open  ssh
9090/tcp open  zeus-admin
MAC Address: 0A:E5:16:D0:BC:B5 (Unknown)

# Nmap done at Mon Jan  9 22:38:09 2023 -- 1 IP address (1 host up) scanned in 144.60 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In addition, the (in)famous SELinux is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enforcing&lt;/code&gt; by default. This adds an additional layer of protection, and will potentially cause a ton of headaches down the line if you need to do anything unconventional by Red Hat’s book.&lt;/p&gt;

&lt;h2 id=&quot;network-services&quot;&gt;Network Services&lt;/h2&gt;
&lt;p&gt;Similar to the Debian review, I am going to document my experience in setting up Nginx and PostgreSQL in Fedora.&lt;/p&gt;

&lt;h3 id=&quot;serving-web-pages-with-nginx&quot;&gt;Serving Web Pages with Nginx&lt;/h3&gt;
&lt;p&gt;Fedora 37’s package repository have Nginx version 1.22.1, which is the current stable version. The installation includes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.service&lt;/code&gt; unit file, but by default it is not enabled. To start the Nginx server, you will need to enable and start the service using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemctl&lt;/code&gt;, and also add HTTP service in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firewall-cmd&lt;/code&gt;. The configuration files come with the package are very close to the upstream.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# tree /etc/nginx
/etc/nginx
├── conf.d
├── default.d
├── fastcgi.conf
├── fastcgi.conf.default
├── fastcgi_params
├── fastcgi_params.default
├── koi-utf
├── koi-win
├── mime.types
├── mime.types.default
├── nginx.conf
├── nginx.conf.default
├── scgi_params
├── scgi_params.default
├── uwsgi_params
├── uwsgi_params.default
└── win-utf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;serving-static-files&quot;&gt;Serving Static Files&lt;/h4&gt;
&lt;p&gt;For static sites, you will simply need to change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; location in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/nginx.conf&lt;/code&gt; and make sure the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx&lt;/code&gt; has access to the files. This is very close to the upstream behavior.&lt;/p&gt;

&lt;h4 id=&quot;serving-dynamic-web-applications&quot;&gt;Serving Dynamic Web Applications&lt;/h4&gt;
&lt;p&gt;For a dynamic web app using nginx -&amp;gt; gunicorn -&amp;gt; flask, Fedora Server turns out to be much more difficult to configure than expected, mostly due to the harsh SELinux security settings.&lt;/p&gt;

&lt;p&gt;Fedora Server’s gunicorn installation doesn’t include a systemd unit file. You can manually create one in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/systemd/system/&lt;/code&gt;, similar to many other Linux distributions. However, due to SELinux, the unit file has to be actually in that directory. A symlink to an unexpected location will cause SELinux to deny access due to lack of Type Enforcement context.&lt;/p&gt;

&lt;p&gt;Similarly, a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_pass&lt;/code&gt; in nginx will also fail. After scrambling around SELinux audit log and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;audit2why&lt;/code&gt; command, we get the following message.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;type=AVC msg=audit(1673673416.968:788): avc:  denied  { name_connect } for  pid=7058 comm=&quot;nginx&quot; dest=8000 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:soundd_port_t:s0 tclass=tcp_socket permissive=0

	Was caused by:
	The boolean httpd_can_network_connect was set incorrectly.
	Description:
	Allow httpd to can network connect

	Allow access by executing:
	# setsebool -P httpd_can_network_connect 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That means SELinux does not allow nginx to connect to upstream server by default. To allow network connect, the “correct” way is to run the following command&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# setsebool -P httpd_can_network_connect 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are lots of online discussion and debate already on whether to turn off SELinux. It is beyond the scope of this review to have deeper discussion about this topic.&lt;/p&gt;

&lt;h3 id=&quot;database-with-postgresql&quot;&gt;Database with PostgreSQL&lt;/h3&gt;
&lt;p&gt;Fedora 37 comes with PostgreSQL version 14.3, which is one major version behind as of this writing. The installation includes a few Fedora customized tools such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql-setup&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql-new-systemd-unit&lt;/code&gt;. Once it is installed, it will put &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql.service&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql@.service&lt;/code&gt; under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/lib/systemd/system&lt;/code&gt;, but no actual database will be created.&lt;/p&gt;

&lt;p&gt;To create the default database with data directory at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/pgsql/data&lt;/code&gt;, simply run the included script and then enable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql&lt;/code&gt; service:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# postgresql-setup --initdb
# systemctl enable postgresql
# systemctl start postgresql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To allow connection over TCP port (5432 by default), the port needs to be explicitly allowed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;firewalld&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# firewall-cmd --permanent --add-port=5432/tcp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For a database with custom data directory, things is a bit more complicated under Fedora 37 Server Edition. There are directions on how to achieve that under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/share/doc/postgresql/README.rpm-dist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You first need to create a new systemd unit file, and initialize the database in the special directory&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# postgresql-new-systemd-unit --unit postgresql@pgdata --datadir /data/pgdata
# postgresql-setup --initdb --unit postgresql@pgdata --port 5433
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once the data directory is created, to make SELinux happy, you will need to set context and enable NIS.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# semanage fcontext -a -t postgresql_db_t &quot;/data/pgdata(/.*)?&quot;
# setsebool -P nis_enabled 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally, for allowing network connection, in addition to changes in typical &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgresql.conf&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pg_hba.conf&lt;/code&gt;, you will also need to open the TCP port.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Fedora 37 Server Edition is a very solid and secure distribution, to the point it is making system administration annoying with SELinux enabled. Most packages are quite up-to-date, but the additional scripts included are not as useful as Debian ones. This is a great Linux distribution for those who are already experienced in Linux.&lt;/p&gt;
</description>
        <pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2023-01-15/fedora-37-server-review/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2023-01-15/fedora-37-server-review/</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Linux Server Review: Debian 11 Bullseye</title>
        <description>&lt;h2 id=&quot;forward&quot;&gt;Forward&lt;/h2&gt;
&lt;p&gt;Recently, I needed to spin up a Linux server instance. Since I have been out of practice for a few years now, I went out to look for a few comprehensive reviews for various Linux distributions. Unfortunately, while that are abundance of Linux reviews, from the great &lt;a href=&quot;https://distrowatch.com&quot;&gt;Distrowatch&lt;/a&gt; to various blogs and Youtube channels, rarely do they focus on server related topics. Considering Linux as a server is what over 90% of people working on Linux actually do, and &lt;em&gt;Linux on desktop&lt;/em&gt;™ is perpetually a year away, the lack of server oriented Linux review is really a sad really. Unsatisfied with this, I decided to write my own.&lt;/p&gt;

&lt;p&gt;This will be the first out of hopefully a few posts to review distributions with a focus on server administration. This post will review Debian 11 Bullseye.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The installation is done using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netinst.iso&lt;/code&gt; image via TUI with only SSH server and standard system utilities installed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/debian_install_software_selection.png&quot; alt=&quot;Debian Install Software Selection&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;root-account&quot;&gt;Root Account&lt;/h3&gt;
&lt;p&gt;During installation, the Debian installer will give you the option to set a password for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user or disable it entirely.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/debian_install_user_passwords.png&quot; alt=&quot;Debian Install Set Root Password&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Setting a non-empty password will enable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user login via password. This is a more traditional setup that many people are familiar with. If one choose to enter an empty password in the process, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user will be disabled. Instead, the regular user to be created in the next step will be part of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; group and can carry out sysadmin work via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; commands. Worth noting that, as a quirk from the Debian installation, if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user is enabled, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; the program will &lt;em&gt;not&lt;/em&gt; be installed by default, and as a result, the regular user created will &lt;em&gt;not&lt;/em&gt; be in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; group.&lt;/p&gt;

&lt;h2 id=&quot;default-security&quot;&gt;Default Security&lt;/h2&gt;
&lt;p&gt;Once installed, Debian 11 has reasonably good out-of-box security. Nmap scan show that only TCP port 22 (SSH) is open. One thing to note is that all other ports are rejected with TCP reset. Depending the school of thought you subscribe to, this might be either the exact right thing to do, or reducing the security by not using drop / no-response, and thus allowing port scanning to move quickly. I was able to scan all 65,535 ports in about 11 seconds.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Nmap 7.93 scan initiated Sat Dec 31 00:11:30 2022 as: nmap -p- -T4 -oN - 192.168.1.53
Nmap scan report for debian.lan (192.168.1.53)
Host is up (0.00054s latency).
Not shown: 65534 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 08:00:27:D2:04:B6 (Oracle VirtualBox virtual NIC)

# Nmap done at Sat Dec 31 00:11:41 2022 -- 1 IP address (1 host up) scanned in 10.85 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In addition, the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd_config&lt;/code&gt; is set to disallow password login for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; account. This adds some more security or annoyance depending on your view.&lt;/p&gt;

&lt;h2 id=&quot;network-services&quot;&gt;Network Services&lt;/h2&gt;
&lt;p&gt;For most developers, you want to hit the ground run in the shortest time possible. This usually means needing to spin up a web server and a database of sorts. Here I review how to install and configure Nginx and PostgreSQL in Debian 11.&lt;/p&gt;

&lt;h3 id=&quot;serving-web-pages-with-nginx&quot;&gt;Serving Web Pages with Nginx&lt;/h3&gt;
&lt;p&gt;Debian 11’s package repository currently contains Nginx version 1.18.0. This is a few version behind, but completely expected. When installed, it will automatically add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.service&lt;/code&gt; as part of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-user.target.wants&lt;/code&gt;. It also come with a very modularized configuration directory.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# tree /etc/nginx/
/etc/nginx/
├── conf.d
├── fastcgi.conf
├── fastcgi_params
├── koi-utf
├── koi-win
├── mime.types
├── modules-available
├── modules-enabled
│   ├── 50-mod-http-geoip.conf -&amp;gt; /usr/share/nginx/modules-available/mod-http-geoip.conf
│   ├── 50-mod-http-image-filter.conf -&amp;gt; /usr/share/nginx/modules-available/mod-http-image-filter.conf
│   ├── 50-mod-http-xslt-filter.conf -&amp;gt; /usr/share/nginx/modules-available/mod-http-xslt-filter.conf
│   ├── 50-mod-mail.conf -&amp;gt; /usr/share/nginx/modules-available/mod-mail.conf
│   ├── 50-mod-stream.conf -&amp;gt; /usr/share/nginx/modules-available/mod-stream.conf
│   └── 70-mod-stream-geoip.conf -&amp;gt; /usr/share/nginx/modules-available/mod-stream-geoip.conf
├── nginx.conf
├── proxy_params
├── scgi_params
├── sites-available
│   └── default
├── sites-enabled
│   └── default -&amp;gt; /etc/nginx/sites-available/default
├── snippets
│   ├── fastcgi-php.conf
│   └── snakeoil.conf
├── uwsgi_params
└── win-utf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;serving-static-files&quot;&gt;Serving Static Files&lt;/h4&gt;
&lt;p&gt;For static pages, one can put the files anywhere. Just make sure the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www-data&lt;/code&gt; have access to the directory and the files within, and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; line in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/sites-available/default&lt;/code&gt; and it is good to go.&lt;/p&gt;

&lt;h4 id=&quot;serving-dynamic-web-applications&quot;&gt;Serving Dynamic Web Applications&lt;/h4&gt;
&lt;p&gt;Unlike static pages, Debian doesn’t include builtin niceties for serving a web app. Use an nginx -&amp;gt; gunicorn -&amp;gt; flask application as an example. To achieve that, you will need to manually create a systemd unit file for gunicorn in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/systemd/system/&lt;/code&gt;, and in nginx site configure file, point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_pass&lt;/code&gt; to the bind address or socket of gunicorn.&lt;/p&gt;

&lt;h3 id=&quot;database-with-postgresql&quot;&gt;Database with PostgreSQL&lt;/h3&gt;
&lt;p&gt;Another common use for a Linux server is to run a relational database. Here I use PostgreSQL as an example for the review.&lt;/p&gt;

&lt;p&gt;Debian 11 comes with PostgreSQL version 13, which is not up to date, but completely serviceable. In addition to the database and client tools, it also included a few Debian customized management tools such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pg_lsclusters&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pg_ctlcluster&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pg_createcluster&lt;/code&gt; that help with cluster management. Upon installation, somewhat surprisingly, it automatically creates a database cluster called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; with data directory at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/postgresql/13/main&lt;/code&gt;. This cluster is configured to start automatically, and allow localhost connection only by default. If this is what you need, you are good to go. Or you can further customize the configuration files under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/postgresql/13/main/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes, a data directory under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var&lt;/code&gt; may not be the best option. It is straightforward to create new cluster with custom data directory, presumably in a separate mount point, using either the included Debian specific &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pg_createcluster&lt;/code&gt; script or PostgreSQL’s builtin &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initdb&lt;/code&gt; command. In addition, the default cluster can be turned off by editing the configure file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/postgresql/13/main/start.conf&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The Debian 11 offers a solid albeit slightly out-of-date Linux server distribution. Its packages includes many small quality-of-life improvements over their corresponding upstream releases. From the perspective of server applications, these choices are certainly the right tradeoff to make. This is definitely a great Linux distribution for servers.&lt;/p&gt;

</description>
        <pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2023-01-05/linux-server-review-debian-11/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2023-01-05/linux-server-review-debian-11/</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>How to Modify Variables from a Callback Function in Python</title>
        <description>&lt;p&gt;I recently came across &lt;a href=&quot;https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_gui/py_trackbar/py_trackbar.html#trackbar&quot;&gt;the trackbar demo&lt;/a&gt; in the &lt;a href=&quot;https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_tutorials.html&quot;&gt;OpenCV-Python Tutorials&lt;/a&gt; as part of my quest of teaching myself computer vision.
This demo shows the usage of the high level GUI features (trackbar in this case) in the OpenCV library.
For the demonstration proposes, the tutorial passes a do-nothing function as the callback handler in the creation of trackbar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cv2.createTrackbar()&lt;/code&gt;.
The trackbar value is then retrieved from a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cv2.getTrackbarPos()&lt;/code&gt;.
This makes me wonder if it is possible to give a trackbar a proper callback function so the change of position can be handled directly inside the callback.&lt;/p&gt;

&lt;h2 id=&quot;using-a-class-method&quot;&gt;Using a class method&lt;/h2&gt;

&lt;p&gt;The straightforward way to enable callback function to communicate with its outside scope is to pass a class method as the callback.
Thus, the demo would look like the following without the need to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cv2.getTrackbarPos()&lt;/code&gt;.
From simplicity, I’m only using one trackbar instead of 4 in the demo.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cv2&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ValWithCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ValWithCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namedWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createTrackbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'GREY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;waitKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'q'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyAllWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, using a dedicated class for such a simple operation seems an overkill to me.
I wonder if there are other simpler and cleaner ways to achieve the same result.
The answer turns out to be yes, but a clean implementation requires the understanding how closure in Python works, and how Python treats mutable and immutable objects differently.&lt;/p&gt;

&lt;h2 id=&quot;name-binding-in-python&quot;&gt;Name binding in Python&lt;/h2&gt;

&lt;p&gt;In Python, by default a function can &lt;strong&gt;access&lt;/strong&gt; a variable outside its scope, but cannot &lt;strong&gt;assign&lt;/strong&gt; a new value to that variable.
For &lt;strong&gt;immutable&lt;/strong&gt; types like integer and float, this means the closure is read only.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;myfunc1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 0
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# this x is now a local variable
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myfunc2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# global x is still 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Furthermore, trying to access a global variable before a (local) assignment will raise an error&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;myfunc3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# UnboundLocalError
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;using-a-global-variable&quot;&gt;Using a global variable&lt;/h2&gt;
&lt;p&gt;To change this behavior, we can declare the variable to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;myfunc4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This gives the another solution to the callback problem.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cv2&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namedWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createTrackbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'GREY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grey&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;waitKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'q'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyAllWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, if you have nested classes or functions, using a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global&lt;/code&gt; will be inconvenient.
In Python 3, there is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nonlocal&lt;/code&gt; keyword to provide more flexible control over the variable scope.
In Python 2, we are out of luck and need to investigate other possible means to do the same.&lt;/p&gt;

&lt;h2 id=&quot;using-a-mutable-type&quot;&gt;Using a mutable type&lt;/h2&gt;
&lt;p&gt;When a function accessing a variable of &lt;strong&gt;mutable&lt;/strong&gt; type like list or dictionary, the behavior changes.
&lt;strong&gt;Assignment&lt;/strong&gt; still cause the variable to bind to a local version, however modifications to the variable itself will be persistent.
Consider the following examples:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;myfunc5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# [0]
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# [1]
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myfunc6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;myfunc6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# UnboundLoacalError
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This behavior prompts another solution to the callback question.
To eliminate repetition, I used a more general function and then bind them use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;functools.partial&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cv2&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;functools&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namedWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createTrackbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'R'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createTrackbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'G'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createTrackbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'image'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;waitKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFF&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'q'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyAllWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Fri, 22 Apr 2016 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2016-04-22/modify_variables_from_callback_in_python/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2016-04-22/modify_variables_from_callback_in_python/</guid>
        
        
        <category>python</category>
        
        <category>opencv</category>
        
      </item>
    
      <item>
        <title>Notes on Hash Table</title>
        <description>&lt;p&gt;This post is my study notes on the algorithms and implementations of hash tables.&lt;/p&gt;

&lt;h2 id=&quot;hash-functions&quot;&gt;Hash Functions&lt;/h2&gt;
&lt;h3 id=&quot;hash-functions-for-strings&quot;&gt;Hash Functions for Strings&lt;/h3&gt;
&lt;p&gt;A common hash function for strings looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// initial value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// implicit mod 2**(sizeof(unsigned)*8)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In particular, the famous &lt;a href=&quot;http://www.cse.yorku.ca/~oz/hash.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;djb2&lt;/code&gt;&lt;/a&gt; hash function by Danial J. Bernstein uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M=5381&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C=33&lt;/code&gt;. The multiplication by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;33&lt;/code&gt; or other value in the form of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2**n + 1&lt;/code&gt; can be done by&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// where n = 5 =&amp;gt; C = 33&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Some argue that multiplication in modern CPUs is fast enough so this is no longer necessary.&lt;/p&gt;

&lt;h2 id=&quot;collision-resolution&quot;&gt;Collision Resolution&lt;/h2&gt;
&lt;p&gt;Collision happens when different keys generate the same hash. The two major methods for collision resolution are separate chaining and open addressing.&lt;/p&gt;

&lt;h3 id=&quot;separate-chaining&quot;&gt;Separate Chaining&lt;/h3&gt;
&lt;p&gt;Separate chaining is conceptually simple: each entry in the hash table is a list or list-like structure (e.g. head cells) so all keys hash to same index are stored in the same list. Adding and deleting keys are simply the list operations on the corresponding list.&lt;/p&gt;

&lt;p&gt;The major downside of separate chaining is the peformance as inserting new entry into the list involves allocating new memory. Following the list may also cause all sorts of performance issue due to non-locality in memory.&lt;/p&gt;

&lt;h3 id=&quot;open-addressing&quot;&gt;Open Addressing&lt;/h3&gt;
&lt;p&gt;Open addressing store all the entries in the bucket array itself. When collision happens, it try to find an unoccupied slot according to some “probe sequence”. The choice of the probe sequences include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;linear probing: simply trying the next slot&lt;/li&gt;
  &lt;li&gt;quadratic probing: index is calculated using some quadratic polynomial (python uses this method)&lt;/li&gt;
  &lt;li&gt;double hashing: next index is calculated by another hash function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One chanlleage in open addressing is when deleting entries, setting the entry back to unoccupied state will break the hash table if there are more entries of the same hash. A common strategy is to set the entry to some dummy state that is different from empty.&lt;/p&gt;

&lt;h2 id=&quot;reading-materials&quot;&gt;Reading Materials&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://algs4.cs.princeton.edu/34hash/&quot;&gt;Chapter 3.4 of Algorithms.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hash_table&quot;&gt;Wikipedia page about Hash Table.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.laurentluce.com/posts/python-dictionary-implementation/&quot;&gt;cPython’s dictionary implementation.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Tue, 26 Jan 2016 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2016-01-26/notes_on_hash_table/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2016-01-26/notes_on_hash_table/</guid>
        
        
        <category>algorithm</category>
        
      </item>
    
      <item>
        <title>Finding XML Root Element Using Boost Property Tree</title>
        <description>&lt;p&gt;Recently, for &lt;a href=&quot;/2015-12-05/using_libxml2_on_supercomputer_considered_harmful/&quot;&gt;various reasons&lt;/a&gt;, I need to convert some XML parsing code from using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boost::property_tree::ptree&lt;/code&gt;. During such migration, one issue arises from the different way two libraries treating the root element of a XML document.&lt;/p&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt;, one is able to get the root element without knowing its name by using the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xmlDocGetRootElement()&lt;/code&gt;. Being spoiled by this feature, our XML files grow a little messier than they otherwise should have and having multiple different names for the root element. In order to be able to process these files, we need the new code to be able to replicate the old behavior.&lt;/p&gt;

&lt;p&gt;This requirement creates some difficulties as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptree::get_child()&lt;/code&gt; requires the name of each node along the path. To be honest, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boost::property_tree&lt;/code&gt; is a general purpose tree structure that supports not only XML but also JSON and INI format. As a result, its XML parser is much more tolerant than a pure XML parser. For example, it will be perfectly happy to parse a file with multiple root elements which most other XML library will complain about. As a side effect, the root element in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptree&lt;/code&gt; does not have special status.&lt;/p&gt;

&lt;p&gt;This means I need to write my own function that finds the root element without referring to its name. Fortunately, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ptree&lt;/code&gt; provide a Container-like interface that allow me to iterate through the (key-node) pairs of any node’s direct sub-nodes. The pair is defined as&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self_type&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typedef&lt;/code&gt; of the node itself. Knowing this, I can simply get the first sub-node from the container. The code snippet looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;boost/property_tree/xml_parser.hpp&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;boost/property_tree/ptree.hpp&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;property_tree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;some_file_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ptree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;read_xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;property_tree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml_parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trim_whitespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ptree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;second&lt;/code&gt; used here because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pt.begin()&lt;/code&gt; returns an iterator that dereference to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::pair&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first&lt;/code&gt; is the node name and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;second&lt;/code&gt; is the sub-node itself.&lt;/p&gt;

&lt;p&gt;Certainly, this code gives you the root element if the XML file is well-formed. If there are multiple root elements in the XML document, this will return the first one. If there is no root element, it will throw an exception as that will cause to dereference a past-the-end iterator.&lt;/p&gt;

</description>
        <pubDate>Sat, 12 Dec 2015 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2015-12-12/finding_doc_root_in_boost_ptree/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2015-12-12/finding_doc_root_in_boost_ptree/</guid>
        
        
        <category>c++</category>
        
        <category>boost</category>
        
        <category>property_tree</category>
        
        <category>XML</category>
        
      </item>
    
      <item>
        <title>Using libxml2 on Supercomputers Considered Harmful</title>
        <description>&lt;p&gt;I was blissfully unaware of a nasty bug in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; and happily using it for my parallel simulated annealing code running on &lt;a href=&quot;http://beagle.ci.uchicago.edu&quot;&gt;Beagle&lt;/a&gt;. That is, until last week when Beagle underwent a system upgrade and all of sudden my code start segfaulting. Upon inspecting the core dump, I was surprised to find out that it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xmlInitParser&lt;/code&gt;, which is in turn called by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xmlParseFile&lt;/code&gt; that was causing the segmentation fault.&lt;/p&gt;

&lt;p&gt;Since Beagle uses different systems for its head nodes and compute nodes, like many supercomputer systems do, my first intuition was that the libxml2 from the head nodes might be no longer work on compute nodes. If that was the case, simply compiling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; from the source using the cross compiler should fix that. Unfortunately, it was not that simple. A freshly compiled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; still causes segfaults.&lt;/p&gt;

&lt;p&gt;A few googles later I landed at &lt;a href=&quot;https://bugzilla.gnome.org/show_bug.cgi?id=609926&quot;&gt;this bugzilla page&lt;/a&gt;. Basically  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; implicitly uses pthreads and somehow statically linking to it might cause the the code to segfault. Even worse, the maintainer refused to fix this bug citing “&lt;a href=&quot;http://www.akkadia.org/drepper/no_static_linking.html&quot;&gt;Static Linking Considered Harmful&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;It is this attitude, not the bug, that made me furious. Surely I understand it is usually a bad practice to statically link some library. But for many supercomputers, statically linking the library is the only viable option. By refusing to fix this bug, the fine people at Gnome simply ignored the constraint we are having in the scientific computing community.&lt;/p&gt;

&lt;p&gt;In an ideal world where the bandwidth, IO, and storage are all infinitely abundant, certainly linking library dynamically would be the correct way to do things. However, many current supercomputers, like IBM BlueGene series or Cray XE series (on which Beagle is based) or newer, uses severely limited compute nodes in order to achieve maximal performance. These “nodes” usually don’t even have their own storage beyond the stripped down kernel in their firmware. Famously, the original IBM BlueGene/L model doesn’t even support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt; calls on the compute node. The only real filesystem they can access is the network shared user filesystem. Hence, it is common practice for the vender to supply compilers that only produces statically linked binary.&lt;/p&gt;

&lt;p&gt;That left me with little choice. Surely I can go down the rabbit hole and try to patch the libxml2 code myself, provided the patch attached in the ticket is still relevant 5 years later. But I guess that won’t be the best use of my time. Since their attitude left me a bitter taste, I’ll declare that using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libxml2&lt;/code&gt; on supercomputers considered harmful, and switch my XML parsing code entirely to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boost::property_tree&lt;/code&gt;. Yes, the code I’m working on contains both C and C++ code. Actually, it contains decades of work by multiple people but that will be a post for another day.&lt;/p&gt;

</description>
        <pubDate>Sat, 05 Dec 2015 00:00:00 +0000</pubDate>
        <link>http://zhlou.github.io/2015-12-05/using_libxml2_on_supercomputer_considered_harmful/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2015-12-05/using_libxml2_on_supercomputer_considered_harmful/</guid>
        
        
        <category>c++</category>
        
        <category>libxml2</category>
        
        <category>libxml</category>
        
        <category>Cray</category>
        
        <category>XML</category>
        
      </item>
    
      <item>
        <title>How to Use Cached Template Loader in Django</title>
        <description>&lt;p&gt;Django’s &lt;a href=&quot;https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/&quot;&gt;deployment checklist&lt;/a&gt; mentioned that using a cached template loader will improve the performance. However, without giving a solid example, the documentation only direct me to its &lt;a href=&quot;https://docs.djangoproject.com/en/1.8/ref/templates/api/#template-loaders&quot;&gt;template loaders docs&lt;/a&gt;. So it’s left to me to do some digging and experimenting.&lt;/p&gt;

&lt;p&gt;The Django documentation describes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cached.Loader&lt;/code&gt; as a wrapper for other “real” loaders. Unlike the more common &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filesystem.Loader&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app_directories.Loader&lt;/code&gt;, which one only needs to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DIRS&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_DIRS&lt;/code&gt; options inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEMPLATES&lt;/code&gt; settings, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cached.Loader&lt;/code&gt; requires a full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loaders&lt;/code&gt; option complete with arguments. The example given by the documentation looks like this&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;TEMPLATES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'BACKEND'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'django.template.backends.django.DjangoTemplates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'DIRS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'templates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'OPTIONS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'loaders'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'django.template.loaders.cached.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.loaders.filesystem.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.loaders.app_directories.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Glancing at this example, which inconspicuously missing the usual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'APP_DIRS': True&lt;/code&gt; setting, one attempts to merge that with existing settings which usually ends up look like this&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;TEMPLATES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'BACKEND'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'django.template.backends.django.DjangoTemplates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'DIRS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'templates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'APP_DIRS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'OPTIONS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'context_processors'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.context_processors.debug'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.context_processors.request'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.contrib.auth.context_processors.auth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.contrib.messages.context_processors.messages'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'loaders'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'django.template.loaders.cached.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;s&quot;&gt;'django.template.loaders.filesystem.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;s&quot;&gt;'django.template.loaders.app_directories.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Unfortunately, this is not the case. This setting will hit you with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ImproerlyConfigured&lt;/code&gt; exception complains about&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app_dirs must not be set when loaders is defined.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;when rendering. After some Googling and experimenting, it turns out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'APP_DIRS'&lt;/code&gt; setting went missing in the example for a reason. Once you specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django.template.loaders.app_directories.Loader&lt;/code&gt; as one of the loaders wrapped in the cached loader, you don’t need (and should not) set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'APP_DIR': True&lt;/code&gt; anymore. Removing that line gives you a happily configured Django. Now the correct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEMPLATE&lt;/code&gt; setting look like this&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;TEMPLATES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'BACKEND'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'django.template.backends.django.DjangoTemplates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'DIRS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'templates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'OPTIONS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'context_processors'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.context_processors.debug'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.template.context_processors.request'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.contrib.auth.context_processors.auth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'django.contrib.messages.context_processors.messages'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'loaders'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'django.template.loaders.cached.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;s&quot;&gt;'django.template.loaders.filesystem.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;s&quot;&gt;'django.template.loaders.app_directories.Loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Thu, 26 Nov 2015 13:53:00 +0000</pubDate>
        <link>http://zhlou.github.io/2015-11-26/django-template-cached-loader/</link>
        <guid isPermaLink="true">http://zhlou.github.io/2015-11-26/django-template-cached-loader/</guid>
        
        
        <category>django</category>
        
        <category>python</category>
        
        <category>deployment</category>
        
      </item>
    
  </channel>
</rss>
