<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ZackadDev</title><link>https://zackad.dev/</link><description>Recent content on ZackadDev</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 16 Nov 2025 08:58:00 +0000</lastBuildDate><atom:link href="https://zackad.dev/feed.xml" rel="self" type="application/rss+xml"/><item><title>Year 2024 in Review</title><link>https://zackad.dev/en/2024/12/30/2024-in-review.html</link><pubDate>Mon, 30 Dec 2024 09:08:03 +0700</pubDate><guid>https://zackad.dev/en/2024/12/30/2024-in-review.html</guid><description>&lt;h2 id="notable-events">Notable Events&lt;/h2>
&lt;ul>
&lt;li>upgrade ssd on macbook&lt;/li>
&lt;li>forking &lt;a href="https://github.com/trivago/prettier-plugin-twig-melody">trivago/prettier-plugin-twig-melody&lt;/a> into &lt;a href="https://github.com/zackad/prettier-plugin-twig">zackad/prettier-plugin-twig&lt;/a>&lt;/li>
&lt;li>receive first sponsorship on github&lt;/li>
&lt;li>become victim of hacked datacenter&lt;/li>
&lt;li>Assetto Corsa run on linux&lt;/li>
&lt;li>failed to replace keyboard switch&lt;/li>
&lt;li>sold motorbike&lt;/li>
&lt;/ul>
&lt;h2 id="tech-stack">Tech Stack&lt;/h2>
&lt;ul>
&lt;li>configure NixOS using flake&lt;/li>
&lt;li>use main domain to host blog post&lt;/li>
&lt;li>use real domain for selfhosted service on home network&lt;/li>
&lt;li>start using frankenphp for personal project&lt;/li>
&lt;li>start using i3wm on nixos with xfce desktop&lt;/li>
&lt;li>replace brave browser with firefox on android&lt;/li>
&lt;li>replace &lt;a href="https://www.photoprism.app/">photoprism&lt;/a> with &lt;a href="https://immich.app/">immich&lt;/a> as selfhosted photo manager&lt;/li>
&lt;li>learning flatpak as package manager&lt;/li>
&lt;li>migrate &lt;code>x86_64&lt;/code> into &lt;code>aarch64&lt;/code> on cloud server&lt;/li>
&lt;li>failed to setup dokku on arm based server (I give up)&lt;/li>
&lt;li>learning various tool for backup and synchronization
&lt;ul>
&lt;li>syncthing&lt;/li>
&lt;li>borg&lt;/li>
&lt;li>borgmatic&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>learn about MusicBrainz Picard application to manage music metadata&lt;/li>
&lt;/ul>
&lt;h2 id="purchases">Purchases&lt;/h2>
&lt;ul>
&lt;li>android phone, not really being used&lt;/li>
&lt;li>docking station for steamdeck&lt;/li>
&lt;li>nvme ssd for steamdeck&lt;/li>
&lt;li>yet another gamepad&lt;/li>
&lt;li>ifixit essentials kit&lt;/li>
&lt;li>1440p monitor&lt;/li>
&lt;li>wireless laser printer (returned due to wrong model)&lt;/li>
&lt;li>pre-order kobo ereader&lt;/li>
&lt;/ul>
&lt;h2 id="entertainment">Entertainment&lt;/h2>
&lt;ul>
&lt;li>learning about rougelike game genre, playing &lt;em>Hades&lt;/em>&lt;/li>
&lt;li>play &lt;em>Yakuza: Like a Dragon&lt;/em> (on hold)&lt;/li>
&lt;/ul></description></item><item><title>My Terminal Emulator Journey</title><link>https://zackad.dev/en/2024/12/28/terminal-emulator-journey.html</link><pubDate>Mon, 30 Dec 2024 08:46:50 +0700</pubDate><guid>https://zackad.dev/en/2024/12/28/terminal-emulator-journey.html</guid><description>&lt;p>Over the years, I use different terminal emulator. Each has their own pros and cons. This is a summary of my experience.&lt;/p>
&lt;h2 id="gnome-terminal">Gnome Terminal&lt;/h2>
&lt;p>First terminal emulator that I use. Comes pre-installed on ubuntu, my first linux distro. At this point, I don&amp;rsquo;t really know about customizing terminal emulator and shell. Mainly used to install or configure system. Has everything I need out of the box (at that point). No obvious cons for my usage. No longer use it since I don&amp;rsquo;t like gnome DE.&lt;/p>
&lt;h2 id="terminator">Terminator&lt;/h2>
&lt;p>My first 3rd party terminal that I install manually. My favorite features is how to manage multiple pane. The hotkey is comfortable and I try to replicate it on other terminal (mostly unsuccessfull). Not really beatiful in term of appearance. Main reason why I abandon this terminal.&lt;/p>
&lt;h2 id="iterm2">iTerm2&lt;/h2>
&lt;p>I consider this as the default terminal emulator for MacOS. Still use it and don&amp;rsquo;t see compelling reason to change to other terminal (for now).&lt;/p>
&lt;h2 id="kitty">Kitty&lt;/h2>
&lt;p>My first terminal that use gpu acceleration. Looks beautiful, fast, and comfortable keyboard shortcut. I abandone this terminal since it PITA to work on remote server (with ssh). There&amp;rsquo;s workaround for it but I&amp;rsquo;m no longer interested on it.&lt;/p>
&lt;h2 id="alacritty">Alacritty&lt;/h2>
&lt;p>My replacement for kitty, and soon I regret this decision. Lacks features such as clickable url, tab, and pane (IIRC). This is the main motivation I learn of tmux. I give up on this setup since to broke color scheme and I can&amp;rsquo;t fix it.&lt;/p>
&lt;h2 id="xfce4-terminal">xfce4-terminal&lt;/h2>
&lt;p>Xfce if my desktop environment of choice when I migrate to manjaro linux after ubuntu abandon Unity DE. I still use it on NixOS even though I mixed it with i3wm. Since I start using tiling window manager feature for tab/pane is not so important for me. Altough it is kinda PITA when opening new terminal it default to home instead into current directory.&lt;/p>
&lt;h2 id="konsole">Konsole&lt;/h2>
&lt;p>The default terminal for steamdeck since it use KDE plasma. Don&amp;rsquo;t really like the visual aspect of this terminal. Configuration via gui (I don&amp;rsquo;t like it), can&amp;rsquo;t get rid of some toolbar/menu. This might be my least favorite terminal I&amp;rsquo;ve used.&lt;/p>
&lt;h2 id="wezterm">WezTerm&lt;/h2>
&lt;p>My current terminal on steamdeck. Still exploring.&lt;/p>
&lt;h2 id="windows-terminal">Windows Terminal&lt;/h2>
&lt;p>This might be my favorite terminal in term of appearance. Unfortunately it on windows, something that I abandon not long ago.&lt;/p>
&lt;h2 id="ghostty">Ghostty&lt;/h2>
&lt;p>Still waiting to be available on nixpkgs or flatpak.&lt;/p></description></item><item><title>How I Fix Docker Unreliability</title><link>https://zackad.dev/en/2024/12/30/fix-docker-unreliability.html</link><pubDate>Mon, 30 Dec 2024 07:55:53 +0700</pubDate><guid>https://zackad.dev/en/2024/12/30/fix-docker-unreliability.html</guid><description>&lt;h2 id="problems">Problems&lt;/h2>
&lt;p>This are the problem I encounter when self-hosting application in docker:&lt;/p>
&lt;ul>
&lt;li>I store my data/media in a NAS which is different machine from the server that run docker. I use samba as protocol of choice since it simplify my setup on multiple device (smartphone, tablet, laptop, desktop). I don&amp;rsquo;t use NFS since it doesn&amp;rsquo;t have authentication protection.&lt;/li>
&lt;li>When my server boot up after power loss, the NAS will be ready AFTER main server where the docker run. This means mounting network share will fail on boot.&lt;/li>
&lt;li>Docker container that rely on network share filesystem will not start properly.&lt;/li>
&lt;li>AFAIK docker cannot auto restart container that failed to start to begin with.&lt;/li>
&lt;/ul>
&lt;h2 id="my-solution">My Solution&lt;/h2>
&lt;h3 id="use-docker-volume-to-mount-network-share">Use docker volume to mount network share&lt;/h3>
&lt;p>Create new docker volume that will mount network share&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>docker volume create &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --driver local &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --opt type&lt;span style="color:#f92672">=&lt;/span>cifs &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --opt device&lt;span style="color:#f92672">=&lt;/span>//your.server.ip.address/data &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --opt o&lt;span style="color:#f92672">=&lt;/span>addr&lt;span style="color:#f92672">=&lt;/span>your.server.ip.address,username&lt;span style="color:#f92672">=&lt;/span>uxxxxxxx,password&lt;span style="color:#f92672">=&lt;/span>***** &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --name samba_data
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Mount volume into service that need it by add following into &lt;code>compose.yaml&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">test&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">docker.io/library/nginx:latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">samba_data:/data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">samba_data&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">external&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="periodically-check-if-theres-docker-container-with-exited-status">Periodically check if there&amp;rsquo;s docker container with exited status&lt;/h3>
&lt;p>Add following line into crontab. Basically it will check if there&amp;rsquo;s docker container with &lt;code>exited&lt;/code> status and the start it every 5 minutes.&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-cron" data-lang="cron">*/5 * * * * docker ps --filter &amp;#34;status=exited&amp;#34; --quiet | xargs --no-run-if-empty docker start
&lt;/code>&lt;/pre>&lt;h3 id="use-autohealhttpsgithubcomwillfarrelldocker-autoheal-to-restart-unhealthy-container">Use &lt;a href="https://github.com/willfarrell/docker-autoheal">autoheal&lt;/a> to restart unhealthy container&lt;/h3>
&lt;p>Start docker container that would whatch container health&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">autoheal&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">docker.io/willfarrell/autoheal:latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#ae81ff">autoheal&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">always&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">AUTOHEAL_INTERVAL=60&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">AUTOHEAL_START_PERIOD=60&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">AUTOHEAL_DEFAULT_STOP_TIMEOUT=10&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">/var/run/docker.sock:/var/run/docker.sock&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Tag container that you want to &lt;em>autoheal&lt;/em>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">test&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">docker.io/library/nginx:latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">samba_data:/data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">healthcheck&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">test&lt;/span>: &lt;span style="color:#ae81ff">curl --fail localhost || exit 1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">labels&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">autoheal=true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">samba_data&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">external&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Hide Fullpath From Project Explorer on Jetbrains IDE</title><link>https://zackad.dev/en/2024/12/28/remove-fullpath-jetbrains-ide.html</link><pubDate>Sat, 28 Dec 2024 08:05:24 +0700</pubDate><guid>https://zackad.dev/en/2024/12/28/remove-fullpath-jetbrains-ide.html</guid><description>&lt;ul>
&lt;li>Open menu &lt;code>Help -&amp;gt; Edit Custom Properties...&lt;/code> or you can use &lt;em>Search Everywhere&lt;/em> feature by double tap &lt;code>Shift&lt;/code> key&lt;/li>
&lt;li>Put this code&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>project.tree.structure.show.url=false
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>Restart IDE&lt;/li>
&lt;/ul>
&lt;p>&lt;figure>&lt;img src="https://zackad.dev/assets/images/jetbrains-ide/before.png"
alt="Before">&lt;figcaption>
&lt;p>Before&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;figure>&lt;img src="https://zackad.dev/assets/images/jetbrains-ide/after.png"
alt="After">&lt;figcaption>
&lt;p>After&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>Ref: &lt;a href="https://stackoverflow.com/questions/40699438/hide-full-path-next-to-project-in-intellij">https://stackoverflow.com/questions/40699438/hide-full-path-next-to-project-in-intellij&lt;/a>&lt;/p></description></item><item><title>How to Fix GPG decrypt on Wezterm intalled via Flatpak</title><link>https://zackad.dev/en/2024/11/18/fix-gpg-on-wezterm-flatpak.html</link><pubDate>Mon, 18 Nov 2024 21:08:11 +0700</pubDate><guid>https://zackad.dev/en/2024/11/18/fix-gpg-on-wezterm-flatpak.html</guid><description>&lt;h2 id="problem">Problem&lt;/h2>
&lt;p>When I try to decrypt my password from &lt;a href="https://www.passwordstore.org/">password-store&lt;/a>, I got following error.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ pass zackad/bitwarden -c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gpg: public key decryption failed: No such device or address
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gpg: decryption failed: No such device or address
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I though that my gpg setup is broken. It turn out the terminal I install (wezterm) via flatpak cannot acces &lt;code>/dev/tty&lt;/code> or something similar. When I run command &lt;code>tty&lt;/code> on the terminal it give me error.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ tty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>not a tty
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is the default permission for wezterm installed via flatpak.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ flatpak info --show-permissions org.wezfurlong.wezterm
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>Context&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>shared&lt;span style="color:#f92672">=&lt;/span>network;ipc;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sockets&lt;span style="color:#f92672">=&lt;/span>x11;wayland;fallback-x11;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>devices&lt;span style="color:#f92672">=&lt;/span>dri;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filesystems&lt;span style="color:#f92672">=&lt;/span>home:ro;xdg-config/wezterm;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>Session Bus Policy&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>org.freedesktop.Flatpak&lt;span style="color:#f92672">=&lt;/span>talk
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>org.freedesktop.Notifications&lt;span style="color:#f92672">=&lt;/span>talk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The device it can access is limited to only &lt;code>dri&lt;/code> (&lt;a href="https://docs.flatpak.org/en/latest/sandbox-permissions.html#device-access">see here for more info&lt;/a>)&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># grant access to application&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ flatpak override --user org.wezfurlong.wezterm --device&lt;span style="color:#f92672">=&lt;/span>all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>--user&lt;/code> option only be needed if you install application as user (not system wide).&lt;/p></description></item><item><title>TIL: You Can Track Playing Time of Non-Steam Game</title><link>https://zackad.dev/en/2023/06/28/til-non-steam-game-playtime-tracking.html</link><pubDate>Sun, 28 Jan 2024 08:03:25 +0700</pubDate><guid>https://zackad.dev/en/2023/06/28/til-non-steam-game-playtime-tracking.html</guid><description>&lt;blockquote>
&lt;p>Update: 2024-01-28&lt;/p>
&lt;p>This trick NO longer work&lt;/p>
&lt;/blockquote>
&lt;p>If you want to track your gaming session (and other application usage) on windows, give &lt;a href="https://strlen.com/procrastitracker/">ProcrastiTracker&lt;/a> a try. In linux I recommend &lt;a href="https://lutris.net/">Lutris&lt;/a>.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>Original Article&lt;/strong>&lt;/p>
&lt;p>If you have &lt;em>non-steam game&lt;/em>[0] added to steam launcher, one feature that missing is ability to track playtime. It turn out that you can simply move your non-steam game into steam library folder and it will recognize the game and add playtime tracking just fine.&lt;/p>
&lt;h2 id="how-to">How To&lt;/h2>
&lt;ul>
&lt;li>Open steam library folder&lt;/li>
&lt;li>You will find several directories (common, compatdata, downloading, etc)
&lt;figure>&lt;img src="https://zackad.dev/assets/images/steam_library-folder.png"
alt="Steam library folder">&lt;figcaption>
&lt;p>Steam library folder&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Move/Copy your game installation folder into &lt;code>common&lt;/code> directory&lt;/li>
&lt;li>Add &amp;ldquo;non-steam game&amp;rdquo; into steam launcher&lt;/li>
&lt;li>Launch game with newly added entry&lt;/li>
&lt;li>If the title is recognized, a new entry will be added by steam
&lt;figure>&lt;img src="https://zackad.dev/assets/images/steam_actual-entry.png"
alt="Config.exe is actual entry I added to steam as launcher">&lt;figcaption>
&lt;p>Config.exe is actual entry I added to steam as launcher&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;figure>&lt;img src="https://zackad.dev/assets/images/steam_added-entry.png"
alt="Steam recognize the title and add new entry">&lt;figcaption>
&lt;p>Steam recognize the title and add new entry&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;/ul>
&lt;p>Some caveats:&lt;/p>
&lt;ul>
&lt;li>Actual game must exist in steam store, otherwise it won&amp;rsquo;t be recognize&lt;/li>
&lt;li>You can NOT use the (automatically) added entry to launch the game. You must use the entry that you manually added
&lt;figure>&lt;img src="https://zackad.dev/assets/images/steam_cannot-launch.png"
alt="You can&amp;rsquo;t use the added entry to lauch the game, but it can track your playtime">&lt;figcaption>
&lt;p>You can&amp;rsquo;t use the added entry to lauch the game, but it can track your playtime&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;/ul>
&lt;p>[0]: refer to game bought outside steam store or &lt;em>&amp;ldquo;other&amp;rdquo;&lt;/em> version&lt;/p></description></item><item><title>I Give Up on Linux Gaming</title><link>https://zackad.dev/en/2022/12/15/i-give-up-on-linux-gaming.html</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2022/12/15/i-give-up-on-linux-gaming.html</guid><description>&lt;p>Over the last few years I&amp;rsquo;ve been using linux desktop as main workspace and upgrade it into relatively powerfull machine. Either for software development, data analysys, and gaming. Unfortunately the gaming part is the most painfull experience for me. It&amp;rsquo;s just unreliable to play games on linux environment. You never know if the game you try to play will run or not.&lt;/p>
&lt;p>Everytime I update my system (kernel update, driver update, application update) something just broke. The game refuse to start. I need to tinker it by checking the logs. Sometimes it works, most of the times it&amp;rsquo;s not. The most frustating part is controller rumble support. Playing racing game without rumble feedback is like missing half of the experience.&lt;/p>
&lt;p>I still keeping my windows installation for games that flat out refuse to run on linux. This dual boot environment also the main pain point for me. I try to use the same directory as steam library between linux and windows version. When it works, I can save storage space by installing the same game twice. Recently this setup is broke on linux. I can&amp;rsquo;t run my games anymore. I might be able to re-install it on other drive/directory, but I don&amp;rsquo;t want to re-download ~50GB data each time the setup broke.&lt;/p>
&lt;p>For now I will uninstall steam from my linux desktop and use windows exclusively for gaming.&lt;/p></description></item><item><title>Build and Configure PHP with phpenv+php-build</title><link>https://zackad.dev/en/2022/11/07/build-and-configure-php.html</link><pubDate>Mon, 07 Nov 2022 07:37:36 +0700</pubDate><guid>https://zackad.dev/en/2022/11/07/build-and-configure-php.html</guid><description>&lt;h2 id="step-1---install-the-tools">Step 1 - Install The Tools&lt;/h2>
&lt;ul>
&lt;li>Install &lt;a href="https://github.com/phpenv/phpenv">phpenv&lt;/a>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ git clone https://github.com/phpenv/phpenv.git ~/.phpenv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Install &lt;a href="https://github.com/php-build/php-build">php-build&lt;/a> as phpenv plugin&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ git clone https://github/com/php-build/php-build.git ~/.phpenv/plugins/php-build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Add phpenv into PATH (put into .profiles/.bashrc/.zshrc or something similar)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>export PATH&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>HOME&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/.phpenv/bin:{&lt;/span>$PATH&lt;span style="color:#e6db74">}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>eval &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#66d9ef">$(&lt;/span>phpenv init -&lt;span style="color:#66d9ef">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Reload your shell / Re-open your terminal&lt;/li>
&lt;/ul>
&lt;h2 id="step-2---update-definitions">Step 2 - Update Definitions&lt;/h2>
&lt;p>We need to update php-build definitions periodically to get the available php versions.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ cd ~/.phpenv/plugins/php-build
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ git fetch
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ git merge origin/master --ff
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-3---compiling">Step 3 - Compiling&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ PHP_BUILD_CONFIGURE_OPTS&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;--with-sodium --with-pgsql --with-pdo-pgsql --with-zip --with-json --with-xml --enable-fpm&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> PHP_BUILD_XDEBUG_ENABLE&lt;span style="color:#f92672">=&lt;/span>off &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> PHP_BUILD_INSTALL_EXTENSION&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;apcu=5.1.22 pcov=1.0.11&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> phpenv install 8.1.12
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-4---switching-version">Step 4 - Switching Version&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># List installed versions&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ phpenv versions
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Switch into specific version&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ phpenv global 8.1.12
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Reclaim Video Memory for Headless Server</title><link>https://zackad.dev/en/2022/10/04/reclaim-video-memory-for-headless-server.html</link><pubDate>Tue, 04 Oct 2022 08:51:18 +0700</pubDate><guid>https://zackad.dev/en/2022/10/04/reclaim-video-memory-for-headless-server.html</guid><description>&lt;p>I bought a &lt;a href="https://www.bee-link.net/products/beelink-ser3-3200u">Beelink SER3&lt;/a> mini pc for my home server. It has 8GB memory and 256GB storage. Barely enough for my use case to run several service such as vaultwarden, nextcloud, freshrss, plex media server and other thing. In the future I might want to install gitlab or youtrack. For that I need to upgrade the memory to atleast 16GB.&lt;/p>
&lt;p>The thing is, it come pre-installed with windows 11 and from the marketing material it is intended for lightweight desktop usage (office suite, watch video) and boasting to be able running at 4K resolution. No wonder that the allocated video memory from RAM is around 2GB. I notice that after replacing windows with archlinux the main memory only read as 5.xGB. I always thought that video memory is done by OS, it turn out I need to configure it in the BIOS. Here&amp;rsquo;s the setting&lt;/p>
&lt;ul>
&lt;li>Enter Bios mode (restart pc and pres &lt;code>del&lt;/code> key), and select &lt;strong>Advanced&lt;/strong> Tab, then select &lt;strong>AMD CBS&lt;/strong>
&lt;figure>&lt;img src="https://zackad.dev/assets/images/gfx-memory/1_amd_cbs.jpg"
alt="Figure 1: Advance Tabs">&lt;figcaption>
&lt;p>Figure 1: Advance Tabs&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Select &lt;strong>NBIO Common Options&lt;/strong>
&lt;figure>&lt;img src="https://zackad.dev/assets/images/gfx-memory/2_nbio_options.jpg"
alt="Figure 2: NBIO Common Options">&lt;figcaption>
&lt;p>Figure 2: NBIO Common Options&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Select &lt;strong>GFX Configuration&lt;/strong>
&lt;figure>&lt;img src="https://zackad.dev/assets/images/gfx-memory/3_gfx_config.jpg"
alt="Figure 3: GFX Configuration">&lt;figcaption>
&lt;p>Figure 3: GFX Configuration&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Change following options
&lt;ul>
&lt;li>Integrated Graphics Controller -&amp;gt; Forces&lt;/li>
&lt;li>UMA Mode -&amp;gt; UMA_SPECIFIED&lt;/li>
&lt;li>UMA Version -&amp;gt; AUTO&lt;/li>
&lt;li>UMA Frame Buffer Size -&amp;gt; &lt;strong>SELECT_YOUR_CHOISE&lt;/strong> (I run this pc as headless server, the smallest choise is 64MB) To be safe I choose 128MB, might need to install DE later on.
&lt;figure>&lt;img src="https://zackad.dev/assets/images/gfx-memory/4_uma.jpg"
alt="Figure 4: UMA Configuration">&lt;figcaption>
&lt;p>Figure 4: UMA Configuration&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>Scrapping Leaflet Marker Data</title><link>https://zackad.dev/en/2022/09/27/scrapping-leaflet-marker-data.html</link><pubDate>Mon, 03 Oct 2022 14:21:00 +0700</pubDate><guid>https://zackad.dev/en/2022/09/27/scrapping-leaflet-marker-data.html</guid><description>&lt;p>This is a snippet to scrap data from leaflet map generated by &lt;code>https://sekolah.data.kemdikbud.go.id/index.php/Cpetasebaran/index/000000/&lt;/code>&lt;/p>
&lt;ul>
&lt;li>Select data you want to scrap
&lt;figure>&lt;img src="https://zackad.dev/assets/images/select_data.png"
alt="Figure 1: Select data to be scrapped">&lt;figcaption>
&lt;p>Figure 1: Select data to be scrapped&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Open developer console on your browser and paste following code&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Retrieve layers data as array
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">layers&lt;/span> &lt;span style="color:#f92672">=&lt;/span> Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">map&lt;/span>.&lt;span style="color:#a6e22e">_layers&lt;/span>).&lt;span style="color:#a6e22e">map&lt;/span>((&lt;span style="color:#a6e22e">key&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">map&lt;/span>.&lt;span style="color:#a6e22e">_layers&lt;/span>[&lt;span style="color:#a6e22e">key&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Filter with popup only
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">points&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">layers&lt;/span>.&lt;span style="color:#a6e22e">filter&lt;/span>((&lt;span style="color:#a6e22e">layer&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">layer&lt;/span>.&lt;span style="color:#a6e22e">_popupHandlersAdded&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Do something with the results
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">results&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">points&lt;/span>.&lt;span style="color:#a6e22e">map&lt;/span>((&lt;span style="color:#a6e22e">point&lt;/span>) =&amp;gt; ({ &lt;span style="color:#a6e22e">coordinate&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">point&lt;/span>.&lt;span style="color:#a6e22e">getLatLng&lt;/span>(), &lt;span style="color:#a6e22e">data&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">point&lt;/span>.&lt;span style="color:#a6e22e">getPopup&lt;/span>().&lt;span style="color:#a6e22e">getContent&lt;/span>() }))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Extract essentials data
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">processed&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">results&lt;/span>.&lt;span style="color:#a6e22e">map&lt;/span>((&lt;span style="color:#a6e22e">item&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Create dummy element for querying DOM
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">element&lt;/span> &lt;span style="color:#f92672">=&lt;/span> document.&lt;span style="color:#a6e22e">createElement&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;div&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">element&lt;/span>.&lt;span style="color:#a6e22e">innerHTML&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">item&lt;/span>.&lt;span style="color:#a6e22e">data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">schoolId&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">element&lt;/span>.&lt;span style="color:#a6e22e">querySelector&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;a&amp;#39;&lt;/span>).&lt;span style="color:#a6e22e">href&lt;/span>.&lt;span style="color:#a6e22e">split&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;/&amp;#39;&lt;/span>).&lt;span style="color:#a6e22e">pop&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">element&lt;/span>.&lt;span style="color:#a6e22e">querySelectorAll&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;li&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">data&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [...&lt;span style="color:#a6e22e">data&lt;/span>].&lt;span style="color:#a6e22e">map&lt;/span>((&lt;span style="color:#a6e22e">el&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">el&lt;/span>.&lt;span style="color:#a6e22e">textContent&lt;/span>.&lt;span style="color:#a6e22e">replace&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;NPSN : &amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>).&lt;span style="color:#a6e22e">replace&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Alamat : &amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">result&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">data&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>(&lt;span style="color:#a6e22e">schoolId&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> { &lt;span style="color:#a6e22e">coordinate&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">item&lt;/span>.&lt;span style="color:#a6e22e">coordinate&lt;/span>, &lt;span style="color:#a6e22e">npsn&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span>[&lt;span style="color:#ae81ff">0&lt;/span>], &lt;span style="color:#a6e22e">nama&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>], &lt;span style="color:#a6e22e">alamat&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span>[&lt;span style="color:#ae81ff">2&lt;/span>], &lt;span style="color:#a6e22e">id&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span>[&lt;span style="color:#ae81ff">3&lt;/span>] }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">localStorage&lt;/span>.&lt;span style="color:#a6e22e">setItem&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;results&amp;#39;&lt;/span>, &lt;span style="color:#a6e22e">JSON&lt;/span>.&lt;span style="color:#a6e22e">stringify&lt;/span>(&lt;span style="color:#a6e22e">processed&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Now we can retrieve the results from &lt;code>localStorage&lt;/code>. Open &lt;strong>Storage&lt;/strong> tabs, navigate to &lt;em>Local Storage&lt;/em>, select and copy
&lt;figure>&lt;img src="https://zackad.dev/assets/images/copy_localstorage.png"
alt="Figure 2: Copy from localStorage">&lt;figcaption>
&lt;p>Figure 2: Copy from localStorage&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/li>
&lt;li>Paste into text editor and remove &lt;code>result:&amp;quot;&lt;/code> at the start of the line and &lt;code>&amp;quot;&lt;/code> from the end of the line. Save as &lt;code>results.json&lt;/code> file.&lt;/li>
&lt;li>Create new file and paste following code, save as &lt;code>json2geo.py&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Original code from: https://gis.stackexchange.com/a/74046&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> sys &lt;span style="color:#f92672">import&lt;/span> argv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> os.path &lt;span style="color:#f92672">import&lt;/span> exists
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> simplejson &lt;span style="color:#66d9ef">as&lt;/span> json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>script, in_file, out_file &lt;span style="color:#f92672">=&lt;/span> argv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>data &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>load(open(in_file))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>geojson &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;type&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;FeatureCollection&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;features&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;type&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Feature&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;geometry&amp;#34;&lt;/span> : {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;type&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Point&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;coordinates&amp;#34;&lt;/span>: [d[&lt;span style="color:#e6db74">&amp;#34;coordinate&amp;#34;&lt;/span>][&lt;span style="color:#e6db74">&amp;#34;lng&amp;#34;&lt;/span>], d[&lt;span style="color:#e6db74">&amp;#34;coordinate&amp;#34;&lt;/span>][&lt;span style="color:#e6db74">&amp;#34;lat&amp;#34;&lt;/span>]],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;properties&amp;#34;&lt;/span> : d,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">for&lt;/span> d &lt;span style="color:#f92672">in&lt;/span> data]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>output &lt;span style="color:#f92672">=&lt;/span> open(out_file, &lt;span style="color:#e6db74">&amp;#39;w&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>json&lt;span style="color:#f92672">.&lt;/span>dump(geojson, output)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Add execute permission with &lt;code>chmod +x json2geo.py&lt;/code>&lt;/li>
&lt;li>Open terminal and run &lt;code>./json2geo.py results.json final-results.geojson&lt;/code>&lt;/li>
&lt;/ul></description></item><item><title>Store Steam Library on Nas Server</title><link>https://zackad.dev/en/2022/09/25/store-steam-library-on-nas-server.html</link><pubDate>Sun, 25 Sep 2022 22:19:41 +0700</pubDate><guid>https://zackad.dev/en/2022/09/25/store-steam-library-on-nas-server.html</guid><description>&lt;p>By default steam library will be installed to your home directory when installed on linux. Unfortunately my drive only 128GB, not enough to install most AAA title. Fortunately I have NAS server with large storage. It would be nice to put game library on this server. That way I can share it between linux and windows (hopefully).&lt;/p>
&lt;h2 id="how-to">How To&lt;/h2>
&lt;ul>
&lt;li>Create NFS share on your NAS. This is an example of my configuration. It can only be accessed from ip address &lt;code>192.168.88.10&lt;/code> (my desktop pc).&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>&amp;#34;/mnt/md0/games&amp;#34; 192.168.88.10(rw,async,insecure,no_subtree_check,no_root_squash)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>Mount your NFS share into local directory. You can use &lt;code>mount&lt;/code> command or add entry on your &lt;code>/etc/fstab&lt;/code>&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code># /etc/fstab
# ...
192.168.88.2:/mnt/md0/games /home/zackad/Games nfs defaults,noatime,users,exec 0 0
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>Make sure that you add &lt;code>exec&lt;/code> at the end of option, otherwise steam will complain about your mount missing execute permission&lt;/li>
&lt;li>Open steam Settings -&amp;gt; Downloads -&amp;gt; Steam Library Folder&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://zackad.dev/assets/images/steam_setting.png" alt="Steam Settings">&lt;/p>
&lt;ul>
&lt;li>Click &amp;lsquo;+&amp;rsquo; button to add library folder&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://zackad.dev/assets/images/steam_storage-manager.png" alt="Add library folder">&lt;/p>
&lt;ul>
&lt;li>Select &amp;lsquo;Let me choose another location&amp;rsquo;&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://zackad.dev/assets/images/steam_add-library.png" alt="Select location">&lt;/p>
&lt;ul>
&lt;li>Choose your folder to store steam library. Make sure that folder you choose is empty.&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://zackad.dev/assets/images/steam_select-directory.png" alt="Select forlder">&lt;/p>
&lt;ul>
&lt;li>Now you can use this new library to store your game or application&lt;/li>
&lt;/ul></description></item><item><title>Configuring Beelink SER3 to Auto Start on Power Loss</title><link>https://zackad.dev/en/2022/09/16/configuring-beelink-ser3-to-auto-start-on-power-loss.html</link><pubDate>Fri, 16 Sep 2022 11:55:00 +0700</pubDate><guid>https://zackad.dev/en/2022/09/16/configuring-beelink-ser3-to-auto-start-on-power-loss.html</guid><description>&lt;ol>
&lt;li>
&lt;p>Power ON your mini-pc and press &lt;code>Del&lt;/code> key on your keyboard until you enter BIOS mode.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Navigate to Advanced tab&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Select AMD CBS menu
&lt;img src="https://zackad.dev/assets/images/1_advance_option.jpg" alt="advance option">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Select FCH Common Options
&lt;img src="https://zackad.dev/assets/images/2_amd_cbs.jpg" alt="AMD CBS">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Select AC Power Loss Options
&lt;img src="https://zackad.dev/assets/images/3_fch_common.jpg" alt="FCH Common Options">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Select your preferred mode when AC Power is loss. In my case I want it to auto turn on when AC power lost and the machine is powered on, so I choose &amp;ldquo;Previous&amp;rdquo;
&lt;img src="https://zackad.dev/assets/images/4_ac_power_loss.jpg" alt="AC Power Loss">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Press &lt;code>F4&lt;/code> key to save the change and exit.&lt;/p>
&lt;/li>
&lt;/ol></description></item><item><title>Installing Aequilibrae plugin on QGIS linux</title><link>https://zackad.dev/en/2022/08/08/install-aequilibrae-on-qgis.html</link><pubDate>Mon, 08 Aug 2022 14:33:00 +0700</pubDate><guid>https://zackad.dev/en/2022/08/08/install-aequilibrae-on-qgis.html</guid><description>&lt;h2 id="problem">Problem&lt;/h2>
&lt;p>Depending on your current setup, you might not be able install and use &lt;a href="https://plugins.qgis.org/plugins/AequilibraE/">Aequilibrae plugin&lt;/a> out of the box. I have this problem on linux and macos system. It works flawlessly on windows system. Just follow the manual and you good to go.&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>It take me quite some time to figure it out what exactly the problem. Basically it come down to:&lt;/p>
&lt;ul>
&lt;li>missing dependency&lt;/li>
&lt;li>bug on download binaries functionality&lt;/li>
&lt;li>incompatible compiled binary version provided by plugin author&lt;/li>
&lt;/ul>
&lt;p>Here the steps I do to fix this problem&lt;/p>
&lt;ul>
&lt;li>Install Aequilibrae with plugin manager. You might have error like this&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>Couldn&amp;#39;t load plugin &amp;#39;AequilibraE&amp;#39; due to an error when calling its classFactory() method
ModuleNotFoundError: No module named &amp;#39;scipy&amp;#39;
Traceback (most recent call last):
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 423, in _startPlugin
plugins[packageName] = package.classFactory(iface)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/__init__.py&amp;#34;, line 32, in classFactory
from .AequilibraEMenu import AequilibraEMenu
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/AequilibraEMenu.py&amp;#34;, line 31, in
from .distribution_procedures import DistributionModelsDialog
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/distribution_procedures/__init__.py&amp;#34;, line 21, in
from .distribution_models_dialog import DistributionModelsDialog
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/distribution_procedures/distribution_models_dialog.py&amp;#34;, line 13, in
from ..matrix_procedures import LoadMatrixDialog, LoadDatasetDialog, DisplayAequilibraEFormatsDialog
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/matrix_procedures/__init__.py&amp;#34;, line 1, in
from .load_matrix_class import LoadMatrix
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/matrix_procedures/load_matrix_class.py&amp;#34;, line 25, in
from scipy.sparse import coo_matrix
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
ModuleNotFoundError: No module named &amp;#39;scipy&amp;#39;
Python version: 3.10.5 (main, Aug 1 2022, 07:53:20) [GCC 12.1.0]
QGIS version: 3.26.1-Buenos Aires Buenos Aires, exported
Python Path:
/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/aequilibrae
/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/aequilibrae
/usr/share/qgis/python
/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python
/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins
/usr/share/qgis/python/plugins
/usr/lib/python310.zip
/usr/lib/python3.10
/usr/lib/python3.10/lib-dynload
/home/zackad/.local/lib/python3.10/site-packages
/usr/lib/python3.10/site-packages
/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python
&lt;/code>&lt;/pre>&lt;p>You need to install some dependencies manually with &lt;code>pip&lt;/code> command. In this case run &lt;code>pip install scipy&lt;/code>. Do the same until there&amp;rsquo;s no error loading the plugin. Restart QGIS for this to take effect.&lt;/p>
&lt;ul>
&lt;li>Right click on Toolbar and make sure that Aequilibrae panel is checked&lt;/li>
&lt;li>Click &amp;ldquo;Download binaries&amp;rdquo;. The version I&amp;rsquo;m using has a bug that prevent me to download binaries. It might have been fixed and upated when you read this article.&lt;/li>
&lt;li>Open file &lt;code>/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/binary_downloader_class.py&lt;/code> and change this on line 27&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">- par = yaml.load(yml)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ par = yaml.safe_load(yml)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Restart QGIS. Now you should be able to download the binaries&lt;/li>
&lt;li>Click &amp;ldquo;GIS -&amp;gt; Desire Line&amp;rdquo; on Aequilibrae panel and you will trigger another error. If you open &amp;ldquo;Log messages&amp;rdquo; panel from &amp;ldquo;View -&amp;gt; Panels -&amp;gt; Log messages&amp;rdquo;, you will find something like this on &amp;ldquo;Python warnings&amp;rdquo; tab.&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>2022-08-08T15:03:07 WARNING warning:/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/AequilibraEMenu.py:55: UserWarning: AequilibraE binaries are not available (&amp;#34;cannot import name &amp;#39;allOrNothing&amp;#39; from &amp;#39;AequilibraE.aequilibrae.aequilibrae.paths&amp;#39; (/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/aequilibrae/aequilibrae/paths/__init__.py)&amp;#34;,)
warn(f&amp;#39;AequilibraE binaries are not available {e.args}&amp;#39;)
traceback: File &amp;#34;&amp;#34;, line 1, in
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 443, in startPlugin
if not _startPlugin(packageName):
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 423, in _startPlugin
plugins[packageName] = package.classFactory(iface)
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/__init__.py&amp;#34;, line 32, in classFactory
from .AequilibraEMenu import AequilibraEMenu
File &amp;#34;/usr/lib/python3.10/site-packages/qgis/utils.py&amp;#34;, line 888, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File &amp;#34;&amp;#34;, line 1027, in _find_and_load
File &amp;#34;&amp;#34;, line 1006, in _find_and_load_unlocked
File &amp;#34;&amp;#34;, line 688, in _load_unlocked
File &amp;#34;&amp;#34;, line 883, in exec_module
File &amp;#34;&amp;#34;, line 241, in _call_with_frames_removed
File &amp;#34;/home/zackad/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/AequilibraEMenu.py&amp;#34;, line 55, in
warn(f&amp;#39;AequilibraE binaries are not available {e.args}&amp;#39;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>Compile aequilibrae binary manually&lt;/li>
&lt;li>Open terminal and navigate to &lt;code>~/.local/share/QGIS/QGIS3/profiles/default/python/plugins/AequilibraE/aequilibrae/aequilibrae/paths&lt;/code> directory&lt;/li>
&lt;li>Type &lt;code>python setup_Assignment.py build_ext --inplace&lt;/code>&lt;/li>
&lt;li>Restart QGIS&lt;/li>
&lt;/ul></description></item><item><title>Reset USB Connection Without Un-pluging on Linux</title><link>https://zackad.dev/en/2022/05/16/reset-usb-connection-without-un-pluging-on-linux.html</link><pubDate>Mon, 16 May 2022 17:26:00 +0700</pubDate><guid>https://zackad.dev/en/2022/05/16/reset-usb-connection-without-un-pluging-on-linux.html</guid><description>&lt;p>I&amp;rsquo;ve been playing games on linux lately. Unfortunately most of them is windows game that I run using steam proton or wine. None of them has native support for linux and has some problem either when launching or terminating. In most cases I&amp;rsquo;m using either SIGKILL or SIGTERM to stop the process. Because of this ungracefull process ternimation my wireless xbox controller going &lt;em>caput&lt;/em> and refuse to re-connect. The solution is easy, just unplug and re-plug the usb wireless receiver.&lt;/p>
&lt;p>The bad news is I&amp;rsquo;m pluging the receiver on the back of my pc and make it cumbersome to do. It would be great if we can just re-connect usb device without physically re-pluging the hardware. If you&amp;rsquo;re using arch linux based distro there&amp;rsquo;s AUR package that can do that, it&amp;rsquo;s called &lt;code>usbreset&lt;/code>.&lt;/p>
&lt;p>Install with your favorite package manager&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ pamac build usbreset
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Find out which usb device you want to reset&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ lsusb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># This is the list of connected usb devive&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">004&lt;/span> Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">003&lt;/span> Device 002: ID 045e:0719 Microsoft Corp. Xbox &lt;span style="color:#ae81ff">360&lt;/span> Wireless Adapter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">003&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">002&lt;/span> Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 003: ID 8087:0029 Intel Corp. AX200 Bluetooth
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 002: ID 04d9:0180 Holtek Semiconductor, Inc. USB-HID Keyboard
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 004: ID 18f8:0fc0 &lt;span style="color:#f92672">[&lt;/span>Maxxter&lt;span style="color:#f92672">]&lt;/span> USB GAMING MOUSE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>From output example above, the xbox wireless receiver on &lt;code>Bus 003&lt;/code> and &lt;code>Device 002&lt;/code>. Now we need to run command&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ usbreset /dev/bus/usb/003/002
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Will output something like this&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Resetting USB device /dev/bus/usb/003/002
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Reset successful
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="reference">Reference:&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://askubuntu.com/a/661">https://askubuntu.com/a/661&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aur.archlinux.org/packages/usbreset">usbreset on AUR&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>How To Run Windows Game with Vanilla Wine on Linux</title><link>https://zackad.dev/en/2022/05/15/how-to-run-windows-game-with-vanilla-wine-on-linux.html</link><pubDate>Sun, 15 May 2022 10:06:00 +0700</pubDate><guid>https://zackad.dev/en/2022/05/15/how-to-run-windows-game-with-vanilla-wine-on-linux.html</guid><description>&lt;h2 id="what">What&lt;/h2>
&lt;p>Gaming on linux getting better and better in the last couple of years thanks to Steam and project like proton. This is my take on how to play windows game that doesn&amp;rsquo;t available on steam or some pirated version to try before buying. Ideally I would use proton to run windows game/application but I can&amp;rsquo;t make it work. Proton/steam always complaint about execute permission on mounted disk. I store most of my data on NAS server mounted with samba or NFS. Whatever tweak I use, steam wont recognize it as valid mount. I can&amp;rsquo;t even use my mounted NAS as steam library folder. This force me to &amp;lsquo;sacrifice&amp;rsquo; litle space on my local drive to be used as steam library folder. Fortunately by using &lt;code>wine&lt;/code> I can run whatever application/game stored in whatever directory/network mounted share.&lt;/p>
&lt;h2 id="why-not-use-lutrisplayonlinuxothers">Why not use Lutris/PlayOnLinux/Others?&lt;/h2>
&lt;p>I have steam installed on my system and don&amp;rsquo;t want to add another application just to launch game/app. All I need is some mechanism to launch windows game/application and add it to steam for centralize game launcher.&lt;/p>
&lt;h2 id="step-by-step">Step by Step&lt;/h2>
&lt;ul>
&lt;li>Install latest version of &lt;code>wine&lt;/code> using your package manager&lt;/li>
&lt;li>Make sure you can run wine from your terminal&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ wine
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Will output something like this&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>wine-7.7
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Create separate prefix for each game/application (optional)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Run following command to create custom prefix directory&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># This will populate wine prefix with all the needed files for wine to run&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ WINEPREFIX&lt;span style="color:#f92672">=&lt;/span>/path_to_your_custom_prefix/.wine_awesome_game winecfg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Install patched &lt;code>dxvk-async&lt;/code> to reduce stutter when playing game (optional)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Download compiled patched version of dxvk-async&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Check &amp;#34;https://github.com/Sporif/dxvk-async/releases&amp;#34; for latest release&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ curl -Lo dxvk-async-1.10.1.tar.gz https://github.com/Sporif/dxvk-async/releases/download/1.10.1/dxvk-async-1.10.1.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Extract downloaded&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ tar -xzf dxvk-async-1.10.1.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Change directory to the new extracted content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd dxvk-async-1.10.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make sure that installer script has execute permission&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ chmod +x setup_dxvk.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Install dxvk-async into wine prefix we created earlier&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ WINEPREFIX&lt;span style="color:#f92672">=&lt;/span>/path_to_your_custom_prefix/.wine_awesome_game ./setup_dxvk.sh install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Install/Run windows game. Now that we have custom wine prefix for game that we want to play, we can install or just copy from windows machine (some game can be run without full re-installation)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Lets say we have installer in Download directory&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd Download
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Run installer with wine prefix we create earlier&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Follow installation proccess&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ WINEPREFIX&lt;span style="color:#f92672">=&lt;/span>/path_to_your_custom_prefix/.wine_awesome_game wine my-game-installer.exe
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Now we can run the game&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Let say we install the game into &amp;#34;~/Games/My Awewome Game&amp;#34; directory. Notice the space in the&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># directory name, we need to escape it&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make sure you run wine from game installation directory, or it might not work as you expected&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd ~/Games/My&lt;span style="color:#ae81ff">\ &lt;/span>Awesome&lt;span style="color:#ae81ff">\ &lt;/span>Game
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make sure to set DXVK_ASYNC=1, this will reduce stutter caused by shader compilation&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ DXVK_ASYNC&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> WINEPREFIX&lt;span style="color:#f92672">=&lt;/span>/path_to_your_custom_prefix/.wine_awesome_game wine game-name.exe
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Creating shell script to launch the game (optional)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env sh
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#75715e"># Create new file and save it as `my-game-launcher.sh`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd ~/Games/My&lt;span style="color:#ae81ff">\ &lt;/span>Awesome&lt;span style="color:#ae81ff">\ &lt;/span>Game
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DXVK_ASYNC&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> WINEPREFIX&lt;span style="color:#f92672">=&lt;/span>/path_to_your_custom_prefix/.wine_awesome_game wine game-name.exe
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>add execute permission with &lt;code>chmod +x my-game-launcher.sh&lt;/code>&lt;/p>
&lt;ul>
&lt;li>Now we can call the launcher from terminal or add it into steam as &amp;lsquo;Non-Steam game&amp;rsquo;. Open terminal and run &lt;code>/path_to/my-game-launcher.sh&lt;/code> to run the launcher.&lt;/li>
&lt;/ul></description></item><item><title>Fixing Slow Boot After Turning Off Swap on Linux</title><link>https://zackad.dev/en/2022/04/23/fixing-slow-boot-after-turning-off-swap-on-linux.html</link><pubDate>Sat, 23 Apr 2022 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2022/04/23/fixing-slow-boot-after-turning-off-swap-on-linux.html</guid><description>&lt;h2 id="why-turning-off-swap">Why Turning-off swap?&lt;/h2>
&lt;p>Most of the time I have terrible experience when using swap. Whenever I have Out Of Memory (OOM) error, my computer freeze and become unusable that I have to hard reset it. Other time when the swap is actively being used, it make my system become unstable and not responsive because the system trying to access data from the swap. It&amp;rsquo;s a slow process that sometime require a few minutes before I can kill some applications to reclaim some memory.&lt;/p>
&lt;h2 id="what-the-problem-now">What The Problem Now?&lt;/h2>
&lt;p>Usually all we need to do to disable swap is simple turning it off with &lt;code>sudo swapoff -a&lt;/code> and then remove swap entry from &lt;code>/etc/fstab&lt;/code>. This will prevent swap partition to be mounted after reboot. Unfortunately this is not the case for me. After rebooting I notice that for some reason, my system trying to mount swap partition that I&amp;rsquo;m already removed from &lt;code>/etc/fstab&lt;/code>. What makes it worst is that I&amp;rsquo;ve deleted the swap partition itself so I can&amp;rsquo;t revert it. This will make my system become slower to boot because it will wait the swap partition to be mount before giving up after 10 seconds timeout.&lt;/p>
&lt;h2 id="the-solution">The Solution&lt;/h2>
&lt;p>After searching on the internet I don&amp;rsquo;t find anything that will fix my problem. Most of the solution basically telling to disable swap with &lt;code>sudo swappoff -a&lt;/code> and removing swap entry from &lt;code>/etc/fstab&lt;/code> which I have already done. The others suggest to check &lt;code>/etc/initfamfs-tools/conf.d/resume&lt;/code> (didn&amp;rsquo;t exist in my system) and rebuild RAM disk with &lt;code>sudo update-initramfs -u&lt;/code> (command not found in my system).&lt;/p>
&lt;p>Fortunately it give me some hints where to look for. I suspect it has to do with grub, so I check &lt;code>/etc/defaults/grub&lt;/code> and found this entry&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>GRUB_CMDLINE_LINUX_DEFAULT&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;amd_iommu=on iommu=pt mitigations=off apparmor=1 security=apparmor resume=UUID=2f391ed3-ca81-469e-a848-5d2b1b846b77 udev.log_priority=3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Notice the &lt;code>resume=UUID=xxxxx&lt;/code> part, this is the old swap partition uuid. So I just remove that part and update grup config with &lt;code>sudo grub-mkconfig -b /boot/grub/grub.cfg&lt;/code> and then reboot.&lt;/p>
&lt;p>And yes, it fix my problem of system trying to mount non existing partition and causing slower booting time.&lt;/p></description></item><item><title>Re-Installing TerraMaster OS (TOS) After It Broke</title><link>https://zackad.dev/en/2021/12/06/re-installing-terramaster-os-tos-after-it-broke.html</link><pubDate>Mon, 06 Dec 2021 11:13:00 +0700</pubDate><guid>https://zackad.dev/en/2021/12/06/re-installing-terramaster-os-tos-after-it-broke.html</guid><description>&lt;h2 id="why">Why?&lt;/h2>
&lt;p>After I update TerraMaster OS (TOS), I&amp;rsquo;m also installing some application that unfortunately got stuck on 50% progress for a long time. The application I want to install are Transmission (bittorent client) and Aria2 (multi protocol download client). Both of them got stuck at 50% progress. With no option to cancel installation process and getting impatient, I decide to reboot my server and all of sudden I can no longer able to access my server. Accessing web control panel got connection refused, accessing ssh also refused.&lt;/p>
&lt;p>At this point my conclusion is that I need to factory reset my server. But wait, it doesn&amp;rsquo;t has reset button and I can&amp;rsquo;t even access it via ssh. The answer is by re-installing the operating system (TOS) itself.&lt;/p>
&lt;h2 id="before-you-start">Before You Start&lt;/h2>
&lt;ul>
&lt;li>Read the documentation/user manual&lt;/li>
&lt;li>Find out if other user has similar problem&lt;/li>
&lt;li>Don&amp;rsquo;t hesitate to ask for help in the internet forum or customer service&lt;/li>
&lt;li>Backup your data if possible&lt;/li>
&lt;/ul>
&lt;p>My first step of re-installing TOS is find out how to do it, and why other people do it in the first place. I found &lt;a href="https://forum.terra-master.com/en/viewtopic.php?t=931">this thread&lt;/a> that someone broke their system after rebooting the server. Similar enough for me. In my case, it might caused by incomplete installation process and make my system corrupt.&lt;/p>
&lt;p>My biggest fear is that I might lose all the data stored on the hard drive if I re-install the TOS. Thanks to this &lt;a href="https://forum.terra-master.com/en/viewtopic.php?t=931#p4607">post&lt;/a> I feel a bit relieved knowing that I won&amp;rsquo;t lose data unless I re-format by drive.&lt;/p>
&lt;h2 id="problem-along-the-way">Problem Along The Way&lt;/h2>
&lt;p>Following &lt;a href="https://forum.terra-master.com/en/viewtopic.php?t=931#p4607">guide&lt;/a> from the user support, I tried to re-install TOS using online installer. I tried this several times but the server is NOT rebooting. Usually after installing the OS it will immediately reboot and start the initialization step. No matter how many times I tried, it still refused to reboot.&lt;/p>
&lt;p>Ok, online installation is not working. Maybe offline installation method might work. I download the latest version of TOS from &lt;a href="https://support.terra-master.com/download/packages?product=F4-210">download center&lt;/a> page (the latest version of TOS when I write this is version 4.2.17) and install it using offline installation method. Same problem, it stuck after installation progress and not rebooting. Maybe older version of TOS might work? So I download and install the previous version of TOS (4.1.xx) and now it reboot after installation process which is a good sign.&lt;/p>
&lt;p>After following initialization step, the server do some system check and rebooting once more. Now the server work fine as intended with all my data still intact. I lose some modification that I make via ssh but that&amp;rsquo;s ok. I can re-configure it later.&lt;/p>
&lt;h2 id="how">How?&lt;/h2>
&lt;p>This is the step I do when installing TOS:&lt;/p>
&lt;ul>
&lt;li>Power down the server, unfortunately it doesn&amp;rsquo;t have reset button. Pressing down power button for several seconds also not make the server turned off. My solution is just unplug the power cable&lt;/li>
&lt;li>Unplug all the hard drive&lt;/li>
&lt;li>Turn on the server&lt;/li>
&lt;li>Access server using web interface, you might need to find out what ip address your server is using whatever method you&amp;rsquo;re comfortable with. In my case, I asign it static ip address in my router&lt;/li>
&lt;li>It wiil prompt you that there is no hard drive attached to the server, keep your server turn on and attach the hard drive. If you have several hard drive, just attach the first one&lt;/li>
&lt;li>Click start to begin installation process&lt;/li>
&lt;li>After some disk checking, the installation will begin. Select &amp;ldquo;Install new TOS&amp;rdquo;&lt;/li>
&lt;li>Select &amp;ldquo;Manual Installation&amp;rdquo; and browse installation package that have been downloaded&lt;/li>
&lt;li>After installation process is done, it wiil reboot and start initialization prcess&lt;/li>
&lt;li>Set your username, password and other thing&lt;/li>
&lt;li>Server will do some self diagnose and fixing itself&lt;/li>
&lt;li>Check if everything is working and your data is safe&lt;/li>
&lt;li>Now you can re-attach your other drive&lt;/li>
&lt;li>You might need to reboot in order for other drives to be mounted properly&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>If going forward is not working, maybe step back a little will do the trick. Using newer version of software usually is a good thing but sometimes older version is more reliable.&lt;/p></description></item><item><title>How to get simple stats from git repository</title><link>https://zackad.dev/en/2021/11/27/how-to-get-simple-stats-from-git-repository.html</link><pubDate>Sat, 27 Nov 2021 07:44:00 +0700</pubDate><guid>https://zackad.dev/en/2021/11/27/how-to-get-simple-stats-from-git-repository.html</guid><description>&lt;h2 id="actual-script">Actual script&lt;/h2>
&lt;p>This script will print commit stats grouped by author in the current git repository. Save into your &lt;code>PATH&lt;/code> e.g &lt;code>~/.local/bin/gstats&lt;/code> and give it execute permission (&lt;code>chmod +x ~/.local/bin/gstats&lt;/code>).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env sh
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>echo &lt;span style="color:#e6db74">&amp;#34;Generating simple stats for this repository&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> author in &lt;span style="color:#66d9ef">$(&lt;/span>git shortlog -s | cut -c8- | xargs&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo -e &lt;span style="color:#e6db74">&amp;#34;\nStats for \&amp;#34;&lt;/span>$author&lt;span style="color:#e6db74">\&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Copied from: https://gist.github.com/eyecatchup/3fb7ef0c0cbdb72412fc&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> git log --shortstat --author&lt;span style="color:#f92672">=&lt;/span>$author &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> | grep -E &lt;span style="color:#e6db74">&amp;#34;fil(e|es) changed&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> | awk &lt;span style="color:#e6db74">&amp;#39;{files+=$1; inserted+=$4; deleted+=$6; delta+=$4-$6; ratio=deleted/inserted} END {printf &amp;#34;Commit stats:\n- Files changed (total).. %s\n- Lines added (total).... %s\n- Lines deleted (total).. %s\n- Total lines (delta).... %s\n- Add./Del. ratio (1:n).. 1 : %s\n&amp;#34;, files, inserted, deleted, delta, ratio }&amp;#39;&lt;/span> -
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="usage">Usage&lt;/h2>
&lt;p>Navigate into your git repository and type &lt;code>gstats&lt;/code> command, this will output something like this.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Generating simple stats for this repository
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stats for &amp;#34;dawamakbar&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Commit stats:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Files changed (total).. 982
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Lines added (total).... 28212
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Lines deleted (total).. 9662
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Total lines (delta).... 18550
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Add./Del. ratio (1:n).. 1 : 0.342478
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Stats for &amp;#34;zackad&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Commit stats:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Files changed (total).. 6201
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Lines added (total).... 128319
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Lines deleted (total).. 61645
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Total lines (delta).... 66674
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>- Add./Del. ratio (1:n).. 1 : 0.480404
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>How to self hosting git with http server</title><link>https://zackad.dev/en/2021/08/28/self-hosted-git-server.html</link><pubDate>Sat, 28 Aug 2021 17:28:00 +0700</pubDate><guid>https://zackad.dev/en/2021/08/28/self-hosted-git-server.html</guid><description>&lt;h2 id="goal">Goal&lt;/h2>
&lt;ul>
&lt;li>Can list git repository similar to &lt;code>http://git.php.net&lt;/code>&lt;/li>
&lt;li>Web insterface used only for public view, security is not a concern&lt;/li>
&lt;li>Easy to provision and tear down&lt;/li>
&lt;/ul>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;ul>
&lt;li>Create directory where to store your repositories&lt;/li>
&lt;li>Run &lt;code>docker run -p 1234:1234 -v /your/repo:/srv/gitweb/repo zackad/gitweb -d&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="manual-steps">Manual Steps&lt;/h2>
&lt;ul>
&lt;li>Create a working directory&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>mkdir git-webhosting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd git-webhosting
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Create Dockerfile with following content&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span>&lt;span style="color:#e6db74"> ruby:2.6-alpine&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">RUN&lt;/span> apk add --no-cache git git-gitweb perl-cgi &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> mkdir -p /srv/gitweb/repo &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> cd /srv/gitweb &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> git init&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">WORKDIR&lt;/span>&lt;span style="color:#e6db74"> /srv/gitweb&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">COPY&lt;/span> entrypoint.sh /srv/gitweb/entrypoint.sh&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">COPY&lt;/span> gitweb_config-example.perl /srv/gitweb/gitweb_config-example.perl&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">EXPOSE&lt;/span>&lt;span style="color:#e6db74"> 1234&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span>&lt;span style="color:#66d9ef">CMD&lt;/span> &lt;span style="color:#e6db74">&amp;#39;./entrypoint.sh&amp;#39;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Create an entrypoint file with following content&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env sh
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">[&lt;/span> -z &lt;span style="color:#e6db74">&amp;#34;&lt;/span>$1&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;span style="color:#f92672">]&lt;/span>; &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Start gitweb server on port 1234&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> git instaweb --httpd&lt;span style="color:#f92672">=&lt;/span>webrick
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Override config file with example, you can override with your own config&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cp gitweb_config-example.perl ./.git/gitweb/gitweb_config.perl
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Prevent container to exit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tail -F .git/gitweb/access.log
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exec &lt;span style="color:#e6db74">&amp;#34;&lt;/span>$@&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Create configuration for gitweb and name it &lt;code>gitweb_config-axample.perl&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-perl" data-lang="perl">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/perl&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">our&lt;/span> $projectroot &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/srv/gitweb/repo&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">our&lt;/span> $git_temp &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/srv/gitweb/.git/gitweb/tmp&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">our&lt;/span> $projects_list &lt;span style="color:#f92672">=&lt;/span> $projectroot;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">our&lt;/span> $projects_list_categories_group &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$feature{&lt;span style="color:#e6db74">&amp;#39;remote_heads&amp;#39;&lt;/span>}{&lt;span style="color:#e6db74">&amp;#39;default&amp;#39;&lt;/span>} &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>];
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Build the docker image with &lt;code>docker build git-hosting:latest .&lt;/code>&lt;/li>
&lt;li>Start container with &lt;code>docker run -p 1234:1234 -v /your/repo/path:/srv/gitweb/repo git-hosting:latest -d&lt;/code>&lt;/li>
&lt;li>Open your browser and access &lt;code>http:127.0.0.1:1234&lt;/code>&lt;/li>
&lt;li>Now you can add your projects into &lt;code>/your/repo/path/&lt;/code> and it will be automatically updated in web interface&lt;/li>
&lt;/ul>
&lt;h2 id="further-action">Further Action&lt;/h2>
&lt;p>You can add this container into your server with some reverse proxy to add SSL for secure access. My main purpose of this system if for mirroring and peace of mind knowing that I can host all my project in an environment where I have total control.&lt;/p></description></item><item><title>Python For Beginner (Not Really Beginner!)</title><link>https://zackad.dev/en/2020/01/13/python-for-beginner-not-really-beginner.html</link><pubDate>Mon, 13 Jan 2020 21:29:00 +0700</pubDate><guid>https://zackad.dev/en/2020/01/13/python-for-beginner-not-really-beginner.html</guid><description>&lt;blockquote>
&lt;p>&lt;strong>WARNING:&lt;/strong> This article is not for beginner in programming, but for python beginner.&lt;/p>
&lt;/blockquote>
&lt;p>If you want to learn python as your second (or 3rd, 4th, nth, &amp;hellip;) language, this guide will give you some advice to manage your code and project structure.&lt;/p>
&lt;h2 id="preview">Preview&lt;/h2>
&lt;link type="text/css" rel="stylesheet" href="https://zackad.dev/assets/asciinema/asciinema-player.css"/>
&lt;asciinema-player src="https://zackad.dev/assets/asciinema/cast/python-get-started.cast" speed="2" idle-time-limit="1">&lt;/asciinema-player>
&lt;script src="https://zackad.dev/assets/asciinema/asciinema-player.js">&lt;/script>
&lt;h2 id="step-1--choosing-python-version">Step 1 — Choosing Python Version&lt;/h2>
&lt;p>Depending on your operating system, python might already installed. Try to type &lt;code>python --version&lt;/code> on your terminal and see which version is installed. Sometime multiple version of python is installed in a single machine (version 2 and version 3). You can check by typing on your terminal&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Check default python version&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Check if python version 3 is installed&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python3 --version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you don&amp;rsquo;t have it installed, please follow the instruction on your operating system how to install python.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># MacOS with homebrew&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>brew install python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Debian based linux distribution&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt get install pthon
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Arch linux&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pacman -S python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># I have no idea how to install python on windows,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Then again I don&amp;#39;t use windows for programming, sorry.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you have to install it manually, please visit &lt;a href="https://www.python.org/downloads/">python download page&lt;/a> and follow the instruction.&lt;/p>
&lt;p>Generally speaking, you should code for python 3 as the target. Unless you need to support a system that only has python 2. Starting with python version 3.3, it has built in tool to manage virtual environment which we need to manage our project in the next step.&lt;/p>
&lt;h2 id="step-2--creating-virtual-environment">Step 2 — Creating Virtual Environment&lt;/h2>
&lt;p>Unlike other language where dependencies are installed locally on project directory (composer on PHP, or npm/yarn on NodeJS), python packages are installed on system wide or user home directory. This will cause conflict when we have project that depend on a package with different version. Let&amp;rsquo;s say we have &lt;strong>Project 1&lt;/strong> that depend on &lt;em>Package A Version 1&lt;/em> and &lt;strong>Project 2&lt;/strong> that depend on &lt;em>Package A Version 2&lt;/em>. When we importing the package it will cause an error because compatibility issue.&lt;/p>
&lt;p>The solution is to isolate these projects into their own environment (or called virtual environment). This will create a directory inside our project with all the binary file that required to run python, including package manager &lt;code>pip&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Create project directory and move into it&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkdir my-python-project
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd my-python-project
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Create new python environment named .venv&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># .venv is the recommended name&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python -m venv .venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Activating virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>source .venv/bin/activate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Deactivating virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deactivate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After activating python virtual environment (venv) we can start installing our dependencies without affecting system python or other environment. When &lt;strong>venv&lt;/strong> is active, this will add a prefix in our shell prompt.&lt;/p>
&lt;h2 id="step-3--managing-dependencies">Step 3 — Managing Dependencies&lt;/h2>
&lt;p>The default package manager for python is pip (in fact I don&amp;rsquo;t even know if there&amp;rsquo;s other). After we activate &lt;code>venv&lt;/code> we can start install/add dependencies into our project.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make sure to activate virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>source .venv/bin/activate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># If this is a new project, start by adding dependencies&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install numpy matplotlib &lt;span style="color:#75715e"># and other dependencies we need&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Save dependencies list into known state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip freeze &amp;gt; requirements.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># If this is a project checked out from other source such as git repo&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># we can install the dependencies with following command.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># (Assuming that &amp;#34;requirements.txt&amp;#34; file is exist in the project)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install -r requirements.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-4--choosing-code-editoride">Step 4 — Choosing Code Editor/IDE&lt;/h2>
&lt;p>Dependending what kind of project we want to build, we might need different editor/IDE. If we just want to fiddle around and explore about python syntax and capabilities, I recommend to use &lt;a href="https://jupyter.org/install.html">jupyter notebook&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>pip install jupyterlab
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>: Whenever we install a new package/dependency, we need to run &lt;code>pip freeze &amp;gt; requirements.txt&lt;/code> to save our dependencies list.&lt;/p>
&lt;/blockquote>
&lt;p>After installing jupyter we can start by running this command to start the notebook.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>jupyter notebook
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Open web browser and visit &amp;ldquo;http://localhost:8888/&amp;rdquo; to access the notebook. Try creating a new notebook by clicking &lt;em>New &amp;gt; Python 3 Notebook&lt;/em>. Now we can star fiddle around.&lt;/p>
&lt;h2 id="step-5--enabling-version-control-optional">Step 5 — Enabling Version Control (Optional)&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Initiating git repository&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add following entries to your &lt;em>.gitignore&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># The name or virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># jupyter notebook checkpoints&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ipynb_checkpoints
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;ul>
&lt;li>use python 3&lt;/li>
&lt;li>different environment for different project&lt;/li>
&lt;li>install dependencies in virtual environment&lt;/li>
&lt;li>use jupyter notebook to fiddle around&lt;/li>
&lt;li>keep project history with git&lt;/li>
&lt;/ul></description></item><item><title>Migrate Blog System From Jekyll To GatsbyJS</title><link>https://zackad.dev/en/2020/01/10/migrate-blog-system-from-jekyll-to-gatsbyjs.html</link><pubDate>Fri, 10 Jan 2020 10:24:00 +0700</pubDate><guid>https://zackad.dev/en/2020/01/10/migrate-blog-system-from-jekyll-to-gatsbyjs.html</guid><description>&lt;blockquote>
&lt;p>&lt;strong>Spoiler Alert:&lt;/strong> NO, I DON&amp;rsquo;T&lt;/p>
&lt;/blockquote>
&lt;p>For something that simple like blog system, the complexities of moving from jekyll to gatsby is not woth it. Here the reason why I&amp;rsquo;m considering migrating my blog system:&lt;/p>
&lt;ul>
&lt;li>I don&amp;rsquo;t use ruby&lt;/li>
&lt;li>I&amp;rsquo;m familiar with javascript and react&lt;/li>
&lt;/ul>
&lt;p>The reason why I don&amp;rsquo;t migrate:&lt;/p>
&lt;ul>
&lt;li>For static content like blog, I would like to avoid javascript if possible&lt;/li>
&lt;li>Migrating process is painfull that I give up midway&lt;/li>
&lt;li>The generated artifact is too large (gatsby =&amp;gt; 2.5Mb, jekyll =&amp;gt; 500Kb)&lt;/li>
&lt;/ul></description></item><item><title>How to Select Fastest Ubuntu Repository Mirror</title><link>https://zackad.dev/en/2018/01/18/how-to-select-fastest-ubuntu-repository-mirror.html</link><pubDate>Thu, 18 Jan 2018 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2018/01/18/how-to-select-fastest-ubuntu-repository-mirror.html</guid><description>&lt;p>Ubuntu has so many mirror repository we can choose. Sometimes the mirror exists in our country that near with our internet provider.&lt;/p>
&lt;h2 id="update">Update&lt;/h2>
&lt;blockquote>
&lt;p>Thank to &lt;a href="https://askubuntu.com/a/9035/562900">this answer&lt;/a> on askubuntu.com we can automatically select fastest (maybe) mirror based on our geographic location.&lt;/p>
&lt;/blockquote>
&lt;p>This configuration will automatically select best mirror based on our geographic location. However, this doesn&amp;rsquo;t necessary mean the fastest server. Add following entry at the top of &lt;code>/etc/apt/source.list&lt;/code> file. You may delete other entry if you wish.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial main restricted universe multiverse
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-updates main restricted universe multiverse
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-backports main restricted universe multiverse
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-security main restricted universe multiverse
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Change &lt;code>xenial&lt;/code> part with your ubuntu version such as &lt;em>trusty, artful, bionic&lt;/em>.&lt;/p>
&lt;hr>
&lt;blockquote>
&lt;p>The following is for other option to select ubuntu mirror.&lt;/p>
&lt;/blockquote>
&lt;h2 id="requirements">Requirements&lt;/h2>
&lt;ul>
&lt;li>Python with pip package manager&lt;/li>
&lt;li>Internet connection (obviously)&lt;/li>
&lt;/ul>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;ul>
&lt;li>Installation from pip (python package manager)&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>sudo pip install apt-select
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Manual installation with git&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>git clone https://github.com/jblakeman/apt-select
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python apt-select/setup.py install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="usage">Usage&lt;/h2>
&lt;p>Open terminal and run &lt;code>apt-select&lt;/code> command. By default, if country code is not provided it will select mirror from US (united stated). Available options are:&lt;/p>
&lt;pre tabindex="0">&lt;code>usage: apt-select [-h] [-C [COUNTRY]] [-t [NUMBER]] [-m [STATUS] | -p]
[-c | -l]
Find the fastest Ubuntu apt mirrors.
Generate new sources.list file.
optional arguments:
-h, --help show this help message and exit
-C [COUNTRY], --country [COUNTRY]
specify a country to test its list of mirrors
used to match country list file names found at mirrors.ubuntu.com
COUNTRY should follow ISO 3166-1 alpha-2 format
default: US
-t [NUMBER], --top-number [NUMBER]
specify number of mirrors to return
default: 1
-m [STATUS], --min-status [STATUS]
return mirrors with minimum status
choices:
up-to-date
one-day-behind
two-days-behind
one-week-behind
unknown
default: up-to-date
-p, --ping-only rank mirror(s) by latency only, disregard status(es)
cannot be used with -m/--min-status
-c, --choose choose mirror from a list
requires -t/--top-num NUMBER where NUMBER &amp;gt; 1
-l, --list print list of mirrors only, don&amp;#39;t generate file
cannot be used with -c/--choose
&lt;/code>&lt;/pre>&lt;p>Copy the generated file into &lt;code>/etc/apt/source.list&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Backup current sources.list&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cp /etc/apt/sources.list /etc/apt/sources.list.backup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Copy the generated file&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cp sources.list /etc/apt/sources.list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Using Gulp To Automatically Run PHPUnit Test After Saving File</title><link>https://zackad.dev/en/2017/12/23/using-gulp-to-automatically-run-phpunit-test-after-saving-file.html</link><pubDate>Sat, 23 Dec 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/12/23/using-gulp-to-automatically-run-phpunit-test-after-saving-file.html</guid><description>&lt;p>One of the most annoying as developer/programmer is to do repetitive task over and over again. Why not just automate it? We are programmer right? It&amp;rsquo;s our job to solve this kind of problem.&lt;/p>
&lt;p>The usual workflow of testing with &lt;code>phpunit&lt;/code> is &lt;em>write test -&amp;gt; run phpunit -&amp;gt; edit source -&amp;gt; run php unit -&amp;gt; repeat&lt;/em>. As we can see, in a single cyclus we run phpunit twice just to check if our source is passing the test. What if after editing the source the test is still failed? We need to edit the source and run phpunit again to check if the test is passing. This kind of repetitive task of cource can be automated right?&lt;/p>
&lt;h2 id="requirement">Requirement&lt;/h2>
&lt;p>&lt;strong>- NodeJS&lt;/strong> with npm&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>Open terminal and change to project directory and install gulp with npm&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>npm install --save-dev gulp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="configuration">Configuration&lt;/h2>
&lt;p>Create a new file with &lt;code>gulpfile.js&lt;/code> name and paste code below.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">gulp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">require&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;gulp&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">exec&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">require&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;child_process&amp;#39;&lt;/span>).&lt;span style="color:#a6e22e">exec&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">gulp&lt;/span>.&lt;span style="color:#a6e22e">task&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;phpunit&amp;#39;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">exec&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;vendor/bin/phpunit --colors=always&amp;#39;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>(&lt;span style="color:#a6e22e">error&lt;/span>, &lt;span style="color:#a6e22e">stdout&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">log&lt;/span>(&lt;span style="color:#a6e22e">stdout&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">gulp&lt;/span>.&lt;span style="color:#a6e22e">task&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;default&amp;#39;&lt;/span>, &lt;span style="color:#66d9ef">function&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">gulp&lt;/span>.&lt;span style="color:#a6e22e">watch&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;**/*.php&amp;#39;&lt;/span>, {&lt;span style="color:#a6e22e">debounceDelay&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">2000&lt;/span>}, [&lt;span style="color:#e6db74">&amp;#39;phpunit&amp;#39;&lt;/span>]);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note: in this configuration we assume that phpunit is installed with composer. If your phpunit is installed globally, you can just type &lt;code>phpunit&lt;/code> as exec parameter.&lt;/p>
&lt;/blockquote>
&lt;h2 id="run-phpunit-test-after-saving-file">Run phpunit test after saving file&lt;/h2>
&lt;p>To run gulp just type &lt;code>node_modules/.bin/gulp&lt;/code> from ternimal. Alternatively we can store this task into &lt;code>package.json&lt;/code> as npm script.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;start&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;gulp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, everytime we need to run gulp we can invoke it with &lt;code>npm start&lt;/code>. With this, after we edit php source and save it, the phpunit will be automatically run and we can monitor the result from terminal.&lt;/p></description></item><item><title>Menghitung Usability Factor Arah Runway Bandara dengan MySQL Database</title><link>https://zackad.dev/id/2017/11/15/menghitung-usability-factor-arah-runway-bandara-dengan-mysql-database.html</link><pubDate>Wed, 15 Nov 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/id/2017/11/15/menghitung-usability-factor-arah-runway-bandara-dengan-mysql-database.html</guid><description>&lt;p>Salah satu tahap dalam perencanaan bandara adalah menentukan arah &lt;em>runway&lt;/em> dengan memperhatikan kondisi angin di lokasi. Dalam artikel singkat ini akan dijelaskan bagaimana menghitung &lt;em>usability factor&lt;/em> dengan menggunakan database sebagai alat bantu analisis.&lt;/p>
&lt;h2 id="apa-saja-yang-dibutuhkan">Apa saja yang dibutuhkan?&lt;/h2>
&lt;ol>
&lt;li>Data arah angin selama 5 tahun terakhir sesuai dengan yang disyaratkan oleh ICAO (International Civil Aviation Organisation). Data ini bisa diperoleh di stasiun pengamatan BMKG terdekat dengan lokasi.&lt;/li>
&lt;li>MySQL database sebagai alat bantu analisis&lt;/li>
&lt;li>MySQL client sebagai antar muka (interface) user dengan system database. (HeidiSQL, MySQL Workbench)&lt;/li>
&lt;/ol>
&lt;h2 id="tahap-1--mempersiapkan-dan-memformat-database">Tahap 1 — Mempersiapkan dan memformat database&lt;/h2>
&lt;p>Pada tahap ini, kita akan mempersiapkan tabel sebagai tempat penyimpanan data. Adapun tabel yang dibutuhkan meliputi :&lt;/p>
&lt;ul>
&lt;li>tabel data angin&lt;/li>
&lt;li>tabel rencana arah runway&lt;/li>
&lt;li>tabel waktu pencatatan data angin (opsional)&lt;/li>
&lt;li>tabel lokasi stasiun pengamatan (opsional)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Catatan:&lt;/strong> tabel yang bersifat opsional akan berguna ketika kita akan melakukan analisis windrose dengan menggunakan aplikasi &lt;strong>WRPlot View&lt;/strong>.&lt;/p>
&lt;/blockquote>
&lt;p>Dari daftar tabel diatas, kita bisa membuat tabel baru dengan perintah:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Membuat tabel data angin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> &lt;span style="color:#e6db74">&amp;#39;data_angin&amp;#39;&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">-- Kolom opsional, berguna untuk export data ke format .lakes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;id_sta_pengamatan&amp;#39;&lt;/span> int(&lt;span style="color:#ae81ff">11&lt;/span>) &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>, &lt;span style="color:#75715e">-- id dari tabel stasiun pengamatan
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;tanggal&amp;#39;&lt;/span> date &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>, &lt;span style="color:#75715e">-- format &amp;#39;YYYY-MM-DD&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;kecepatan_angin&amp;#39;&lt;/span> double &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>, &lt;span style="color:#75715e">-- satuan Knot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;arah_angin&amp;#39;&lt;/span> int(&lt;span style="color:#ae81ff">11&lt;/span>) &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#75715e">-- satuan derajat (°) dengan 0° = utara
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>) ENGINE&lt;span style="color:#f92672">=&lt;/span>InnoDB &lt;span style="color:#66d9ef">DEFAULT&lt;/span> CHARSET&lt;span style="color:#f92672">=&lt;/span>utf8;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Membuat tabel arah runway
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> &lt;span style="color:#e6db74">&amp;#39;arah_runway&amp;#39;&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) ENGINE&lt;span style="color:#f92672">=&lt;/span>InnoDB &lt;span style="color:#66d9ef">DEFAULT&lt;/span> CHARSET&lt;span style="color:#f92672">=&lt;/span>utf8;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="tahap-2--menginput-data">Tahap 2 — Menginput data&lt;/h2>
&lt;h2 id="tahap-3--membuat-fungsi-analisis">Tahap 3 — Membuat fungsi analisis&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Overwrite existing function
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">DROP&lt;/span> &lt;span style="color:#66d9ef">FUNCTION&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> &lt;span style="color:#f92672">`&lt;/span>is_crosswind&lt;span style="color:#f92672">`&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">DELIMITER&lt;/span> &lt;span style="color:#f92672">//&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Check if wind component is a crosswind to runway direction based on tresshold value
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">FUNCTION&lt;/span> &lt;span style="color:#f92672">`&lt;/span>is_crosswind&lt;span style="color:#f92672">`&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>tresshold&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Knot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>runwayDirection&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Degree (°)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windDirection&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Degree (°)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windSpeed&lt;span style="color:#f92672">`&lt;/span> DOUBLE &lt;span style="color:#75715e">-- Knot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">-- Return 1 if crosswind, 0 if not
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">RETURNS&lt;/span> integer(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">LANGUAGE&lt;/span> &lt;span style="color:#66d9ef">SQL&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">DETERMINISTIC&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">CONTAINS&lt;/span> &lt;span style="color:#66d9ef">SQL&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SQL&lt;/span> &lt;span style="color:#66d9ef">SECURITY&lt;/span> &lt;span style="color:#66d9ef">DEFINER&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">COMMENT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">BEGIN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> angelDeg double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> angelRad double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> crossWind double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Calculate minimum angel between 2 crossing line
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- https://math.stackexchange.com/questions/341749/how-to-get-the-minimum-angle-between-two-crossing-lines
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">set&lt;/span> angelDeg &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">abs&lt;/span>(&lt;span style="color:#66d9ef">abs&lt;/span>(&lt;span style="color:#f92672">`&lt;/span>runwayDirection&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windDirection&lt;span style="color:#f92672">`&lt;/span>) &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">180&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- convert angel Degree to Radian
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">set&lt;/span> angelRad &lt;span style="color:#f92672">=&lt;/span> (pi()&lt;span style="color:#f92672">/&lt;/span>&lt;span style="color:#ae81ff">180&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> angelDeg;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">set&lt;/span> crossWind &lt;span style="color:#f92672">=&lt;/span> sin(angelRad) &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windSpeed&lt;span style="color:#f92672">`&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> crossWind &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#f92672">`&lt;/span>tresshold&lt;span style="color:#f92672">`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">then&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">END&lt;/span> &lt;span style="color:#f92672">//&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">DELIMITER&lt;/span> ;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="tahap-4--menghitung-usability-factor">Tahap 4 — Menghitung usability factor&lt;/h2>
&lt;h2 id="referensi">Referensi&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.archerfieldairport.com.au/Downloads/Masterplan2011/TP1_Wind%20Usability%20Analysis.pdf">http://www.archerfieldairport.com.au/Downloads/Masterplan2011/TP1_Wind%20Usability%20Analysis.pdf&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Dengerin Spotify Tanpa Iklan Di PC (No crack, no premium)</title><link>https://zackad.dev/id/2017/11/12/dengerin-spotify-tanpa-iklan-no-crack-no-premium.html</link><pubDate>Sun, 12 Nov 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/id/2017/11/12/dengerin-spotify-tanpa-iklan-no-crack-no-premium.html</guid><description>&lt;p>Inilah cara paling mudah dengerin spotify tanpa terganggu iklan. Tanpa instal software tambahan, tanpa upgrade ke premium, dan tanpa bajak akun punya orang lain.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Disclaimer:&lt;/strong> cara ini tidak mengaktifkan fitur premium yang lain seperti offline mode, high quality streaming, dll.&lt;/p>
&lt;/blockquote>
&lt;h2 id="daftar-host-list-yang-akan-di-blok">Daftar host list yang akan di blok&lt;/h2>
&lt;ul>
&lt;li>Buka web browser dan akses &lt;code>https://github.com/zackad/dotfiles/blob/master/hosts.d/ads_spotify.conf&lt;/code> atau &lt;a href="https://github.com/zackad/dotfiles/blob/master/hosts.d/ads_spotify.conf">klik disini&lt;/a>&lt;/li>
&lt;li>Copy isi file tersebut (kurang lebih seperti dibawah ini)&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code># BLock ads host for spotify
# host list taken from https://www.reddit.com/r/Piracy/comments/4kn6rq/comprehensive_guide_to_blocking_ads_on_spotify/
127.0.0.1 adclick.g.doublecklick.net
127.0.0.1 adeventtracker.spotify.com
127.0.0.1 ads-fa.spotify.com
127.0.0.1 analytics.spotify.com
127.0.0.1 audio2.spotify.com
127.0.0.1 b.scorecardresearch.com
127.0.0.1 bounceexchange.com
127.0.0.1 bs.serving-sys.com
127.0.0.1 content.bitsontherun.com
127.0.0.1 core.insightexpressai.com
127.0.0.1 crashdump.spotify.com
127.0.0.1 d2gi7ultltnc2u.cloudfront.net
127.0.0.1 d3rt1990lpmkn.cloudfront.net
127.0.0.1 desktop.spotify.com
127.0.0.1 doubleclick.net
127.0.0.1 ds.serving-sys.com
127.0.0.1 googleadservices.com
127.0.0.1 googleads.g.doubleclick.net
127.0.0.1 gtssl2-ocsp.geotrust.com
127.0.0.1 js.moatads.com
127.0.0.1 log.spotify.com
127.0.0.1 media-match.com
127.0.0.1 omaze.com
127.0.0.1 open.spotify.com
127.0.0.1 pagead46.l.doubleclick.net
127.0.0.1 pagead2.googlesyndication.com
127.0.0.1 partner.googleadservices.com
127.0.0.1 pubads.g.doubleclick.net
127.0.0.1 redirector.gvt1.com
127.0.0.1 s0.2mdn.net
127.0.0.1 securepubads.g.doubleclick.net
127.0.0.1 spclient.wg.spotify.com
127.0.0.1 tpc.googlesyndication.com
127.0.0.1 v.jwpcdn.com
127.0.0.1 video-ad-stats.googlesyndication.com
127.0.0.1 weblb-wg.gslb.spotify.com
127.0.0.1 www.googleadservices.com
127.0.0.1 www.googletagservices.com
127.0.0.1 www.omaze.com
&lt;/code>&lt;/pre>&lt;blockquote>
&lt;p>&lt;strong>Note:&lt;/strong> Untuk daftar list yang uptodate, cek &lt;a href="https://github.com/zackad/dotfiles/blob/master/hosts.d/ads_spotify.conf">disini&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="edit-file-host">Edit file host&lt;/h2>
&lt;p>&lt;strong>Windows user&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Buka notepad (text editor) dengan hak akses administrator&lt;/li>
&lt;li>Buka file &lt;code>C:\Windows\system32\drivers\etc\hosts&lt;/code>&lt;/li>
&lt;li>Tambahkan kode diatas di bagian bawah file&lt;/li>
&lt;li>Save&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Linux/MacOS user&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Buka text editor dengan hak akses superuser (sudo)&lt;/li>
&lt;li>Buka file &lt;code>/etc/hosts&lt;/code>&lt;/li>
&lt;li>Tambahkan kode diatas pada bagian bawah file&lt;/li>
&lt;li>Save&lt;/li>
&lt;/ul>
&lt;p>Setelah file berhasil disimpan, sebaiknya restart Spotify kalau sebelumnya telah dibuka. Sekarang tiap kali kita mendengarkan musik dengan spotify, tidak ada lagi iklan yang mengganggu karena telah diblok dengan file host kita.&lt;/p>
&lt;h2 id="referensi">Referensi&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.reddit.com/r/Piracy/comments/4kn6rq/comprehensive_guide_to_blocking_ads_on_spotify/">https://www.reddit.com/r/Piracy/comments/4kn6rq/comprehensive_guide_to_blocking_ads_on_spotify/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>How to Extend Line with ArcGIS</title><link>https://zackad.dev/en/2017/10/07/how-to-extend-line.html</link><pubDate>Sat, 07 Oct 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/10/07/how-to-extend-line.html</guid><description>&lt;p>Example of how to extend line feature (eg. road digitation) in order to cleanup the dangels using ArcGIS 10.1.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> arcpy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arcpy&lt;span style="color:#f92672">.&lt;/span>env&lt;span style="color:#f92672">.&lt;/span>workspase &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;path/to/workspase&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arcpy&lt;span style="color:#f92672">.&lt;/span>ExtendLine_edit(&lt;span style="color:#e6db74">&amp;#34;dataset.shp&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;distance&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;EXTENSION&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="extend-line-example-stand-alone-script">Extend Line Example (Stand-alone script)&lt;/h2>
&lt;p>Clean up street centerlines that were digitized without having set proper snapping environments.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name: ExtendLine.py&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Description: Clean up street centerlines that were digitized without having&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># set proper snapping environmnets&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Author: ESRI&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Import system modules&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> arcpy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> arcpy &lt;span style="color:#f92672">import&lt;/span> env
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Set environments settings&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>env&lt;span style="color:#f92672">.&lt;/span>workspase &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;C:/data&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make backup copy of streets feature class, since modification with the Editing tools below is permanent&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>streets &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;street.shp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>streetsBackup &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;C:/output/streetsBackup.shp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arcpy&lt;span style="color:#f92672">.&lt;/span>CopyFeatures_management(streets, streetsBackup)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Trim street lines to clean up the dangles&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arcpy&lt;span style="color:#f92672">.&lt;/span>TrimLine_edit(streets, &lt;span style="color:#e6db74">&amp;#34;10 Feet&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;KEEP_SHORT&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Extend street lines to clean up the dangles&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arcpy&lt;span style="color:#f92672">.&lt;/span>ExtendLine_edit(streets, &lt;span style="color:#e6db74">&amp;#34;15 Feet&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;EXTENSION&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="reference">Reference&lt;/h2>
&lt;ul>
&lt;li>help file of ArcMap 10.1&lt;/li>
&lt;/ul></description></item><item><title>SQL Function to Check Crosswind</title><link>https://zackad.dev/en/2017/09/26/sql-function-to-check-crosswind.html</link><pubDate>Tue, 26 Sep 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/09/26/sql-function-to-check-crosswind.html</guid><description>&lt;p>A simple function to check if a wind component is crosswind for airport runway direction planning. Using MySQL as database engine and analysis tool, this function can help to simplify checking usability factor of runway direction with given meteorogical data.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">DROP&lt;/span> &lt;span style="color:#66d9ef">FUNCTION&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> &lt;span style="color:#f92672">`&lt;/span>is_crosswind&lt;span style="color:#f92672">`&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">DELIMITER&lt;/span> &lt;span style="color:#f92672">//&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Check if wind component is a crosswind to runway direction based on tresshold value
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">FUNCTION&lt;/span> &lt;span style="color:#f92672">`&lt;/span>is_crosswind&lt;span style="color:#f92672">`&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>tresshold&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Knot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>runwayDirection&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Degree
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windDirection&lt;span style="color:#f92672">`&lt;/span> DOUBLE, &lt;span style="color:#75715e">-- Degree
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windSpeed&lt;span style="color:#f92672">`&lt;/span> DOUBLE &lt;span style="color:#75715e">-- Knot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">-- Return 1 if crosswind, 0 if not
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">RETURNS&lt;/span> integer(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">LANGUAGE&lt;/span> &lt;span style="color:#66d9ef">SQL&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">DETERMINISTIC&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">CONTAINS&lt;/span> &lt;span style="color:#66d9ef">SQL&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SQL&lt;/span> &lt;span style="color:#66d9ef">SECURITY&lt;/span> &lt;span style="color:#66d9ef">DEFINER&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">COMMENT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">BEGIN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> angelDeg double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> angelRad double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">declare&lt;/span> crossWind double;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Calculate minimum angel between 2 crossing line
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- https://math.stackexchange.com/questions/341749/how-to-get-the-minimum-angle-between-two-crossing-lines
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">set&lt;/span> angelDeg &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">abs&lt;/span>(&lt;span style="color:#66d9ef">abs&lt;/span>(&lt;span style="color:#f92672">`&lt;/span>runwayDirection&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windDirection&lt;span style="color:#f92672">`&lt;/span>) &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">180&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- convert angel Degree to Radian
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">set&lt;/span> angelRad &lt;span style="color:#f92672">=&lt;/span> (pi()&lt;span style="color:#f92672">/&lt;/span>&lt;span style="color:#ae81ff">180&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> angelDeg;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">set&lt;/span> crossWind &lt;span style="color:#f92672">=&lt;/span> sin(angelRad) &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#f92672">`&lt;/span>windSpeed&lt;span style="color:#f92672">`&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> crossWind &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#f92672">`&lt;/span>tresshold&lt;span style="color:#f92672">`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">then&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">end&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">END&lt;/span> &lt;span style="color:#f92672">//&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">DELIMITER&lt;/span> ;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Configuring Mapserver With NGINX Using Fast CGI</title><link>https://zackad.dev/en/2017/09/06/configuring-mapserver-with-nginx-using-fast-cgi.html</link><pubDate>Wed, 06 Sep 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/09/06/configuring-mapserver-with-nginx-using-fast-cgi.html</guid><description>&lt;p>Mapserver is an Open Source platform for publishing spatial data and interactive mapping application to the web. In this tutorial we will using &lt;code>nginx&lt;/code> as reverse proxy to forward request to mapserver cgi process in the backgraound.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;ul>
&lt;li>Mapserver (available in ubuntu main repository 16.04 and above)&lt;/li>
&lt;li>nginx webserver&lt;/li>
&lt;/ul>
&lt;p>This tutorial assuming that mapserver is installed in as &lt;em>/usr/bin/mapserv&lt;/em>, if your mapserver installed in different path, please adapt accordingly.&lt;/p>
&lt;h2 id="configure-mapserver-as-cgi-worker-with-spawn-fcgi">Configure Mapserver as cgi worker with spawn-fcgi&lt;/h2>
&lt;p>Install spawn-fcgi if not already installed.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get install spawn-fcgi
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="fast-cgi-config">Fast CGI config&lt;/h2>
&lt;p>Running mapserver as cgi service. Create file in &lt;em>/etc/init.d/mapserv&lt;/em> with superuser privilege. Put this content and save.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env sh
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#75715e">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># description: Mapserver Service Manager&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># processname: lt-mapserv&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># pidfile: /var/run/mapserv.pid&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Source function library.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#. /etc/init.d/functions&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Check that networking is up.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#. /etc/sysconfig/network&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">[&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&lt;/span>$NETWORKING&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;no&amp;#34;&lt;/span> &lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exit &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>PREFIX&lt;span style="color:#f92672">=&lt;/span>/usr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME&lt;span style="color:#f92672">=&lt;/span>mapserv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>PID&lt;span style="color:#f92672">=&lt;/span>/var/run/mapserv.pid
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DAEMON&lt;span style="color:#f92672">=&lt;/span>$PREFIX/bin/spawn-fcgi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DAEMON_OPTS&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34; -a 127.0.0.1 -p 9999 -F 4 -u www-data -U www-data -P &lt;/span>$PID&lt;span style="color:#e6db74"> &lt;/span>$PREFIX&lt;span style="color:#e6db74">/bin/mapserv&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>start &lt;span style="color:#f92672">()&lt;/span> &lt;span style="color:#f92672">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo -n $&lt;span style="color:#e6db74">&amp;#34;Starting &lt;/span>$NAME&lt;span style="color:#e6db74"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exec $DAEMON $DAEMON_OPTS &amp;gt;&amp;gt; /dev/null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> daemon --pidfile $PID
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RETVAL&lt;span style="color:#f92672">=&lt;/span>$?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">[&lt;/span> $RETVAL -eq &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stop &lt;span style="color:#f92672">()&lt;/span> &lt;span style="color:#f92672">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo -n $&lt;span style="color:#e6db74">&amp;#34;Stopping &lt;/span>$NAME&lt;span style="color:#e6db74"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> killproc -p $PID
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#make sure all mapservers are closed&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> pkill -f lt-mapserv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RETVAL&lt;span style="color:#f92672">=&lt;/span>$?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">[&lt;/span> $RETVAL -eq &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">]&lt;/span> ; &lt;span style="color:#66d9ef">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rm -f $PID
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>restart &lt;span style="color:#f92672">()&lt;/span> &lt;span style="color:#f92672">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># See how we were called.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&lt;/span>$1&lt;span style="color:#e6db74">&amp;#34;&lt;/span> in
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stop&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> status&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> status lt-mapserv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RETVAL&lt;span style="color:#f92672">=&lt;/span>$?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> restart&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> restart
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> *&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo $&lt;span style="color:#e6db74">&amp;#34;Usage: &lt;/span>$0&lt;span style="color:#e6db74"> {start|stop|status|restart}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RETVAL&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">esac&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>exit $RETVAL
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add execute permission to the file.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo chmod +x /etc/init.d/mapserv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Start mapserver service with command&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo /etc/init.d/mapserv start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="nginx-configuration">Nginx configuration&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-nginx" data-lang="nginx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">server&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">listen&lt;/span> &lt;span style="color:#ae81ff">80&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">listen&lt;/span> &lt;span style="color:#e6db74">[::]:80&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">server_name&lt;/span> &lt;span style="color:#e6db74">mapserver.local&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">add_header&lt;/span> &lt;span style="color:#e6db74">Access-Control-Allow-Origin&lt;/span> &lt;span style="color:#e6db74">*&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">location&lt;/span> &lt;span style="color:#e6db74">/&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Load from /etc/init.d/mapserv
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">fastcgi_pass&lt;/span> 127.0.0.1:&lt;span style="color:#ae81ff">9999&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">include&lt;/span> &lt;span style="color:#e6db74">fastcgi_params&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">fastcgi_param&lt;/span> &lt;span style="color:#e6db74">SCRIPT_NAME&lt;/span> &lt;span style="color:#e6db74">/usr/bin/mapserv&lt;/span>$fastcgi_script_name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="url-rewrite">URL Rewrite&lt;/h2>
&lt;p>From nginx configuration file above, we can add rewrite rule to simplify our resource url. Without rewrite, the url would become&lt;/p>
&lt;pre tabindex="0">&lt;code>http://mapserver-example.com/?map=/path/to/mapfile.map
&lt;/code>&lt;/pre>&lt;p>If we don&amp;rsquo;t want to expose sensitive information such as mapfile location, we can hide it using url rewrite.
From configuration file above, add the following code to location block&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-nginx" data-lang="nginx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">rewrite&lt;/span> &lt;span style="color:#e6db74">^/(.*)&lt;/span>$ &lt;span style="color:#e6db74">/?map=/path/to/location/of/mapfile.map&lt;/span>$1 &lt;span style="color:#e6db74">break&lt;/span>;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So the configuration file would become&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-nginx" data-lang="nginx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Server block
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">location&lt;/span> &lt;span style="color:#e6db74">/&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Load from /etc/init.d/mapserv
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">fastcgi_pass&lt;/span> 127.0.0.1:&lt;span style="color:#ae81ff">9999&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Rewrite url to hide mapfile path
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#f92672">rewrite&lt;/span> &lt;span style="color:#e6db74">^/(.*)&lt;/span>$ &lt;span style="color:#e6db74">/?map=/path/to/location/of/mapfile.map&lt;/span>$1 &lt;span style="color:#e6db74">break&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">include&lt;/span> &lt;span style="color:#e6db74">fastcgi_params&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">fastcgi_param&lt;/span> &lt;span style="color:#e6db74">SCRIPT_NAME&lt;/span> &lt;span style="color:#e6db74">/usr/bin/mapserv&lt;/span>$fastcgi_script_name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="reference">Reference&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://dotrem.blogspot.co.id/2013/06/mapservernginxfastcgi-on-ubuntu.html">http://dotrem.blogspot.co.id/2013/06/mapservernginxfastcgi-on-ubuntu.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>How To Install Allmark - The Markdown Webserver</title><link>https://zackad.dev/en/2017/09/06/allmark-the-markdown-webserver.html</link><pubDate>Wed, 06 Sep 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/09/06/allmark-the-markdown-webserver.html</guid><description>&lt;p>allmark is a fast, standalone markdown web server for Linux, Mac OS and Windows written in go.&lt;/p>
&lt;p>allmark is a file-system-centric markdown web server. You can &lt;strong>point it at any directory that contains markdown files&lt;/strong> and it will immediately start a web-server that serves the rendered HTML content of the markdown file to you.&lt;/p>
&lt;h3 id="step-1--installing-allmark-webserver">Step 1 — Installing allmark webserver&lt;/h3>
&lt;ul>
&lt;li>Download the binary file from &lt;a href="http://allmark.io/bin">this page&lt;/a>&lt;/li>
&lt;li>Select the right version based on your system. If you use desktop computer, you may have 64bit system&lt;/li>
&lt;li>Use &lt;code>chmod&lt;/code> to add execute permission.&lt;/li>
&lt;li>Copy the downloaded file to &lt;code>/usr/local/bin/allmark&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>All that step can be written to&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl http://allmark.io/bin/files/allmark_linux_amd64 &amp;gt; allmark
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod +x allmark
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo mv allmark /usr/local/bin/allmark
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-2--running-allmark-webserver">Step 2 — Running allmark webserver&lt;/h2>
&lt;p>It is recommended to setup configuration wether globally (in your home directory) or locally (on your repository). In this guide, we will config allmark to local repository. Run this command to generate allmark settings.&lt;/p>
&lt;ul>
&lt;li>Change to your (clonned) repository&lt;/li>
&lt;li>Init the setting command&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd path/to/your/repository
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>allmark init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Open &lt;code>.allmark/config&lt;/code> file with your text editor and search the following line and change the &amp;ldquo;Enabled&amp;rdquo; key to &lt;code>true&lt;/code> to enabling livereload when we are editing the content.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;LiveReload&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;Enabled&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}&lt;span style="color:#960050;background-color:#1e0010">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Start allmark server with command. This will automatically open new page on your default web browser to show the content. If not, please open &lt;code>htttp://localhost:33001&lt;/code> on your browser.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>allmark serve
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Now you can start editing the markdown file on your repository.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Note :&lt;/strong> if you have rename/add/delete file/folder on your repository, you may need to restart your allmark webserver for those changes to take effect.&lt;/p>
&lt;/blockquote>
&lt;h2 id="step-3--stopping-and-restarting-allmark-webserver">Step 3 — Stopping and Restarting allmark webserver&lt;/h2>
&lt;p>If you want to stop or restart allmark webserver, simply to press &lt;kbd>Ctrl&lt;/kbd>+&lt;kbd>C&lt;/kbd> to stop the server. And type command &lt;code>allmark serve&lt;/code> then press &lt;kbd>Enter&lt;/kbd> to start server again.&lt;/p>
&lt;h2 id="reference">Reference&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/andreaskoch/allmark">https://github.com/andreaskoch/allmark&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>How to Setup Android Development Environment With React Native on Ubuntu 16.04</title><link>https://zackad.dev/en/2017/09/06/setup-android-development-environment-with-react-native-on-ubuntu.html</link><pubDate>Wed, 06 Sep 2017 00:00:00 +0000</pubDate><guid>https://zackad.dev/en/2017/09/06/setup-android-development-environment-with-react-native-on-ubuntu.html</guid><description>&lt;p>Getting started with android development using react-native.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Warning :&lt;/strong> This article may contain outdated/inacurate information. Please refer to latest documentation.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;p>In this guide, we won&amp;rsquo;t install android studio since we will use standard text editor such as &lt;strong>atom&lt;/strong>, &lt;strong>sublime text&lt;/strong> or even &lt;strong>gedit&lt;/strong>. There&amp;rsquo;s no need to install full blown IDE to develop android with &lt;code>react-native&lt;/code>. Since all the necessacy tool and process will be using command line. That&amp;rsquo;s why we want to install minimal amount of tool to save more storage space. Not only that, we won&amp;rsquo;t install android virtual device (avd) to save more space and use actual device as testing and debug device.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note :&lt;/strong> it is recommended to use actual device instead of virtual device.&lt;/p>
&lt;/blockquote>
&lt;h2 id="step-1--installing-java-development-kit-jdk">Step 1 — Installing Java Development Kit (JDK)&lt;/h2>
&lt;p>We&amp;rsquo;ll need java in order to compile source code to apk file. To install java, open your terminal and run following command :&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get install openjdk-8-jdk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will install all the necessary package to start developing java application, in this case android application.&lt;/p>
&lt;p>There&amp;rsquo;s no particular reason why we use &lt;code>openjdk-8&lt;/code>, if you need to use older/newer version or other java sdk feel free to install those.&lt;/p>
&lt;h2 id="step-2--installing-nodejs-and-npm">Step 2 — Installing NodeJS and NPM&lt;/h2>
&lt;p>We need to install nodejs and npm in order to use react-native since react is nodejs module. We will install stable version from ppa maintained by NodeSource (not from ubuntu repository).&lt;/p>
&lt;p>For the most recent LST (branch 6.x)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will adding PPA into our repository list. Now we need to update package list and installing nodejs into our system.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get install nodejs npm
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To verify that nodejs and npm is successfully installed, run the following command.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nodejs --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>npm -version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will output something like&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Output of nodejs --version&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>v6.10.0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Output of npm -version&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>3.10.10
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-3--install-and-setup-android-sdk-command-line-tools-only">Step 3 — Install and Setup Android SDK (Command Line Tools only)&lt;/h2>
&lt;h3 id="create-a-new-folder-in-your-home-directory-named-android">Create a new folder in your home directory named &lt;em>Android&lt;/em>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkdir Android
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="download-and-extract-android-sdk-file-into-android-directory">Download and extract Android sdk file into &lt;em>Android&lt;/em> directory&lt;/h3>
&lt;blockquote>
&lt;p>Go to &lt;a href="https://developer.android.com/studio/index.html#downloads">this page&lt;/a> to download command line tools or we can use &lt;a href="https://dl.google.com/android/repository/tools_r25.2.3-linux.zip">this link&lt;/a> as of &lt;strong>2017-03-17&lt;/strong>.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd ~/Android
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>wget https://dl.google.com/android/repository/tools_r25.2.3-linux.zip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unzip tools_r25.2.3-linux.zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="add-android-sdk-into-system-path">Add android sdk into system PATH&lt;/h3>
&lt;p>Now, we have to add android sdk into our PATH so we can use these command from anywhere. Open file &lt;code>.bashrc&lt;/code> from our home directory with text editor. We can use &lt;code>nano&lt;/code> or &lt;code>vim&lt;/code> to edit this file right from terminal.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nano ~/.bashrc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, add the following line to the end of file to add android sdk into PATH.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>export ANDROID_HOME&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>HOME&lt;span style="color:#e6db74">}&lt;/span>/Android
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export PATH&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>PATH&lt;span style="color:#e6db74">}&lt;/span>:&lt;span style="color:#e6db74">${&lt;/span>ANDROID_HOME&lt;span style="color:#e6db74">}&lt;/span>/tools
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export PATH&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>PATH&lt;span style="color:#e6db74">}&lt;/span>:&lt;span style="color:#e6db74">${&lt;/span>ANDROID_HOME&lt;span style="color:#e6db74">}&lt;/span>/platform-tools
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We need to restart terminal application for these to take effect.&lt;/p>
&lt;h3 id="installing-the-right-sdk-version">Installing the right sdk version&lt;/h3>
&lt;p>React Native require android version 6 (Marshmallow) ro run, so we need to install sdk tool version 23. After restarting terminal application, we&amp;rsquo;ll install the necessary sdk tool.&lt;/p>
&lt;p>Run this command to open android sdk manager.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>android
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will open a new window. From here we can select what package to be installed.&lt;/p>
&lt;p>&lt;img src="https://zackad.dev/assets/images/a5kN8gy.png" alt="SDK Manager">&lt;/p>
&lt;p>Please make sure that following tool is checked before we click &lt;em>Install Package&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Tools/Android SKD Tools Rev.25.xx (265 MB)&lt;/li>
&lt;li>Tools/Android SKD Platform-tools Rev.25.xx (7.3 MB)&lt;/li>
&lt;li>Tools/Android SDK Build-tools Rev 23.0.1 (37.3 MB)&lt;/li>
&lt;li>Android 6.0 (API 23)/SDK Platform (67.2 MB)&lt;/li>
&lt;li>Android 6.0 (API 23)/Google APIs (176 KB)&lt;/li>
&lt;li>Extras/Android Support Repository (322.7 MB)&lt;/li>
&lt;/ul>
&lt;h2 id="step-4--installing-react-native">Step 4 — Installing React Native&lt;/h2>
&lt;p>Now, we can install react native command line tool with npm. It is recommended to install this tool globally, so you may need superuser permission. From the terminal, run this command to install react-native-cli.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo npm install -g react-native-cli
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To verify that react-native successfully installed, run this command to show help message.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>react-native --help
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>Note :&lt;/strong> we don&amp;rsquo;t need &lt;em>-cli&lt;/em> suffix here.&lt;/p>
&lt;/blockquote>
&lt;h2 id="step-5--initiating-react-native-application">Step 5 — Initiating React Native Application&lt;/h2>
&lt;p>Use the React Native command line interface to generate a new React Native project called &amp;ldquo;AwesomeProject&amp;rdquo;, then run react-native run-android inside the newly created folder.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>react-native init AwesomeProject
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd AwesomeProject
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>react-native run-android
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If everything is set up correctly, you should see your new app running in your Android device shortly.&lt;/p>
&lt;h2 id="step-6--connecting-android-device-to-computer">Step 6 — Connecting Android Device to Computer&lt;/h2>
&lt;h3 id="enable-debugging-over-usb">Enable Debugging over USB&lt;/h3>
&lt;p>Most Android devices can only install and run apps downloaded from Google Play, by default. You will need to enable USB Debugging on your device in order to install your app during development.&lt;/p>
&lt;p>To enable USB debugging on your device, you will first need to enable the &amp;ldquo;Developer options&amp;rdquo; menu by going to &lt;strong>Settings → About phone&lt;/strong> and then tapping the Build number row at the bottom seven times. You can then go back to &lt;strong>Settings → Developer options&lt;/strong> to enable &amp;ldquo;USB debugging&amp;rdquo;.&lt;/p>
&lt;h3 id="plug-in-our-device-via-usb">Plug in our device via USB&lt;/h3>
&lt;p>Let&amp;rsquo;s now set up an Android device to run our React Native projects. Go ahead and plug in your device via USB to your development machine.&lt;/p>
&lt;p>Next, check the manufacturer code by using lsusb (on mac, you must first &lt;code>install lsusb&lt;/code>). lsusb should output something like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ lsusb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">002&lt;/span> Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">002&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 003: ID 22b8:2e76 Motorola PCS
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">004&lt;/span> Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">003&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>These lines represent the USB devices currently connected to your machine.&lt;/p>
&lt;p>You want the line that represents your phone. If you&amp;rsquo;re in doubt, try unplugging your phone and running the command again:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ lsusb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">002&lt;/span> Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">002&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">004&lt;/span> Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">003&lt;/span> Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You&amp;rsquo;ll see that after removing the phone, the line which has the phone model (&amp;ldquo;Motorola PCS&amp;rdquo; in this case) disappeared from the list. This is the line that we care about.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>Bus &lt;span style="color:#ae81ff">001&lt;/span> Device 003: ID 22b8:2e76 Motorola PCS
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>From the above line, you want to grab the first four digits from the device ID:&lt;/p>
&lt;p>&lt;code>22b8:2e76&lt;/code>&lt;/p>
&lt;p>In this case, it&amp;rsquo;s &lt;code>22b8&lt;/code>. That&amp;rsquo;s the identifier for Motorola.&lt;/p>
&lt;p>You&amp;rsquo;ll need to input this into your udev rules in order to get up and running:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>echo SUBSYSTEM&lt;span style="color:#f92672">==&lt;/span>&lt;span style="color:#e6db74">&amp;#34;usb&amp;#34;&lt;/span>, ATTR&lt;span style="color:#f92672">{&lt;/span>idVendor&lt;span style="color:#f92672">}==&lt;/span>&lt;span style="color:#e6db74">&amp;#34;22b8&amp;#34;&lt;/span>, MODE&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0666&amp;#34;&lt;/span>, GROUP&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;plugdev&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> | sudo tee /etc/udev/rules.d/51-android-usb.rules
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Make sure that you replace 22b8 with the identifier you get in the above command.&lt;/p>
&lt;p>Now check that your device is properly connecting to ADB, the Android Debug Bridge, by running adb devices.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ adb devices
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>List of devices attached
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>emulator-5554 offline &lt;span style="color:#75715e"># Google emulator&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14ed2fcc device &lt;span style="color:#75715e"># Physical device&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Seeing device in the right column means the device is connected. You must have &lt;strong>only one device connected&lt;/strong> at a time.&lt;/p>
&lt;h3 id="running-our-app">Running our app&lt;/h3>
&lt;p>Type the following in your command prompt to install and launch your app on the device:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ react-native run-android
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>If you get a &amp;ldquo;bridge configuration isn&amp;rsquo;t available&amp;rdquo; error, see &lt;a href="https://facebook.github.io/react-native/#using-adb-reverse">Using adb reverse&lt;/a>.
Hint : You can also use the React Native CLI to generate and run a Release build (e.g. react-native run-android &amp;ndash;configuration Release).&lt;/p>
&lt;/blockquote>
&lt;h3 id="connecting-to-the-development-server">Connecting to the development server&lt;/h3>
&lt;p>You can also iterate quickly on a device by connecting to the development server running on your development machine. There are several ways of accomplishing this, depending on whether you have access to a USB cable or a Wi-Fi network.&lt;/p>
&lt;h4 id="method-1--using-adb-reverse-recommended">Method 1 — Using adb reverse (recommended)&lt;/h4>
&lt;p>You can use this method if your device is running Android 5.0 (Lollipop), it has USB debugging enabled, and it is connected via USB to your development machine.&lt;/p>
&lt;p>Run the following in a command prompt:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ adb reverse tcp:8081 tcp:8081
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can now use &lt;code>Reload JS&lt;/code> from the React Native in-app Developer menu without any additional configuration.&lt;/p>
&lt;h4 id="method-2--connect-via-wi-fi">Method 2 — Connect via Wi-Fi&lt;/h4>
&lt;p>You can also connect to the development server over Wi-Fi. You&amp;rsquo;ll first need to install the app on your device using a USB cable, but once that has been done you can debug wirelessly by following these instructions. You&amp;rsquo;ll need your development machine&amp;rsquo;s current IP address before proceeding.&lt;/p>
&lt;p>Open a terminal and type &lt;code>/sbin/ifconfig&lt;/code> to find your machine&amp;rsquo;s IP address.&lt;/p>
&lt;ul>
&lt;li>Make sure your laptop and your phone are on the same Wi-Fi network.&lt;/li>
&lt;li>Open your React Native app on your device.&lt;/li>
&lt;li>You&amp;rsquo;ll see a red screen with an error. This is OK. The following steps will fix that.&lt;/li>
&lt;li>Open the in-app Developer menu.&lt;/li>
&lt;li>Go to Dev Settings → Debug server host for device.&lt;/li>
&lt;li>Type in your machine&amp;rsquo;s IP address and the port of the local dev server (e.g. 10.0.1.1:8081).&lt;/li>
&lt;li>Go back to the Developer menu and select Reload JS.&lt;/li>
&lt;/ul>
&lt;h2 id="step-7--installing-react-native-application-into-device">Step 7 — Installing React Native Application into Device&lt;/h2>
&lt;p>Now that we have setup all the development tools, all we need to do is to test/install our app into device. Please make sure that we have already connecting our device with computer using USB connection.&lt;/p>
&lt;p>If we have problem during initiating application with command&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>react-native run-android
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>we can manually install apk file using adb. Run this command to install our app into android device.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb install android/app/build/outputs/apk/app-debug.apk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we want to start developing, we have to start react server and enabling livereload from in app menu. To start react server, enter into root directory of our react project and run this command.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>npm start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To enabling live reload :&lt;/p>
&lt;ul>
&lt;li>open our app that has already installed&lt;/li>
&lt;li>press option button and select &lt;strong>Enable Live Reload&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="reference">Reference&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://facebook.github.io/react-native/docs/running-on-device.html">https://facebook.github.io/react-native/docs/running-on-device.html&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://facebook.github.io/react-native/docs/getting-started.html">https://facebook.github.io/react-native/docs/getting-started.html&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>