<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>oky is okay</title>
    <description>oky.moe is a place for oky to write about various small projects they&apos;ve worked on
</description>
    <link>https://oky.moe/</link>
    <atom:link href="https://oky.moe/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 11 Dec 2025 08:20:38 -0800</pubDate>
    <lastBuildDate>Thu, 11 Dec 2025 08:20:38 -0800</lastBuildDate>
    <generator>Jekyll v4.3.2</generator>
    
      
        <item>
          <title>A philosophy for window management</title>
          <description>&lt;p&gt;its taken me 20+ years , but i’ve
finally distilled my usage of my WM down to a core set of principles that focus
on efficiency and predictability.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href=&quot;/images/xmonad_brutal.png&quot;&gt;&lt;img src=&quot;/images/xmonad_brutal.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;quick spec&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;one window per workspace, occassionally a vertical split for two windows&lt;/li&gt;
  &lt;li&gt;direct access to any workspace via keyboard shortcuts&lt;/li&gt;
  &lt;li&gt;pinned workspaces per monitor, with [1-7] on the left, [8,9,0,\] on the right and [u,i,o,p] / [z,x,c,v] are allowed on either monitor&lt;/li&gt;
  &lt;li&gt;mouse movement is deliberate: switching to a workspace does not move the mouse&lt;/li&gt;
  &lt;li&gt;i can move the mouse or throw windows between monitors with a single shortcut&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;why&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the main feature is the ability to summon the exact window i want and display
it fullscreen&lt;/p&gt;

&lt;p&gt;my workflow revolves around workspaces. each one holds a single fullscreen
window. generally, i’ll have somewhere between ten and twenty workspaces. i’ll
occassionally use a vertical split and show two windows at once.&lt;/p&gt;

&lt;p&gt;i have &lt;em&gt;pinned workspaces&lt;/em&gt; that only display on a specific monitor. summoning a
pinned workspace will change what is shown on that monitor, but it will not
move the mouse or window focus to that monitor.&lt;/p&gt;

&lt;p&gt;this makes it really easy to call up reference material or logs on the side
without disrupting whatever i’m doing in the main flow.&lt;/p&gt;

&lt;p&gt;the rest of my workspaces are unpinned and can float to whichever monitor&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;keybindings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;mod-[workspace]&lt;/em&gt; to jump to any workspace and &lt;em&gt;mod-shift-[workspace]&lt;/em&gt; to move a window to a workspace&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;mod-[h,l]&lt;/em&gt; to focus either monitor and &lt;em&gt;mod-shift-[h,l]&lt;/em&gt; to move windows&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;mod-[j,k]&lt;/em&gt; to change the focused window&lt;/li&gt;
  &lt;li&gt;mod-delete to kill a window&lt;/li&gt;
  &lt;li&gt;ctrl-space to summon the quick launcher&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;other reading:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/my-history-with-linux/&quot;&gt;my history with gnu/linux&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/linux-applications/&quot;&gt;apps i use&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/okayzed/xmonad-config&quot;&gt;my xmonad config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>Sat, 29 Nov 2025 00:00:00 -0800</pubDate>
          <link>https://oky.moe/a-philosophy-for-window-management/</link>
          <guid isPermaLink="true">https://oky.moe/a-philosophy-for-window-management/</guid>
          
          
          <category>code</category>
          
        </item>
      
    
      
    
      
    
      
        <item>
          <title>a robozzle solver</title>
          <description>&lt;p&gt;Many years ago, a friend of mine showed me Robozzle and good times were had.
Recently, I was looking for puzzles in the F-Droid store and Robozzle popped
up.  After doing a few dozen of them, like any good coder, I wondered: how easy
would it be to automate this?&lt;/p&gt;

&lt;h2 id=&quot;what-is-robozzle-anyways&quot;&gt;What is Robozzle, anyways?&lt;/h2&gt;

&lt;p&gt;In Robozzle, you play the part of an evil programmer who has to code the
instructions for their robot to steal all the stars on a 16x12 board. Since you
spent all your time in evil school instead of robot school, the robot doesn’t
have many instructions: it can move forward, turn, draw a color on the board or
call a routine. Each square of the board can be empty, red, blue or green.  If
the robot goes to an empty square, it falls off and perishes. Since the robot
can recognize colors, it can be told to conditionally execute an instruction
only on squares of a given color. The robot can also modify the board by
coloring a square to a different color, which acts as a sort of “memory”
for the robot.&lt;/p&gt;

&lt;p&gt;An example program might be: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F1: ^ R&amp;lt; F1&lt;/code&gt; which means: go forward, turn left
on red squares and then call F1 again. Surprisingly, this small set of
instructions can do a lot of things.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imgur.com/c7eFrLd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;how-difficult-is-writing-a-solver&quot;&gt;How difficult is writing a solver?&lt;/h3&gt;

&lt;p&gt;The largest program that can be written consists of 5 tapes of 10 instructions.&lt;/p&gt;

&lt;p&gt;So, given all of the above, how easy is it to write a program to solve a given
board configuration? A brute force program would essentially be: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N**K&lt;/code&gt; where K
is the number of available operations. On a single colored board with one
routine, there might be only a handful instructions: forward, turn left, turn
right, call F1. However, on a three colored board, with 5 routines, the number
of instructions would be: (4 operations + 5 sub funcs + 3 write colors) * 3
colors = 36 potential instructions. This is noticeably harder to brute force.
In small experiments, brute force takes too long for 7 instructions on this
type of board.&lt;/p&gt;

&lt;h3 id=&quot;a-random-algorithm&quot;&gt;A Random Algorithm&lt;/h3&gt;

&lt;p&gt;Instead of brute force, we can look for smarter alternatives. One popular
category is randomized algorithms. What’s surprising about randomized
algorithms is that they can actually do pretty well in exploring the solution
space.  For my robozzle solver, I wrote a genetic algorithm that evolves and
mutates candidates until it finds one that solves the puzzle.&lt;/p&gt;

&lt;p&gt;The genetic algorithm I used is reasonably simple, it has a few features:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evolution&lt;/strong&gt;: the algorithm starts by spawning random candidates. It then
scores those candidates and picks the top 50, mutates them and scores the
parents + their mutations and trims to the top 50 again. This is called a
&lt;em&gt;strain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fitness&lt;/strong&gt;: the scoring of a candidate is based on 2 factors: what percentage
of stars are collected + the percentage of squares visited. This rewards
exploring more of the board. In order to reward exploration towards stars, each
tile’s score is based on its travel distance from the nearest star.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutation&lt;/strong&gt;: there are 3 types of mutations: 1) over-write random spots with
new instructions, 2) randomly fill a subroutine and 3) randomly swap
instructions. All 3 mutation types are run on a candidate and then inserted
back into the pool.&lt;/p&gt;

&lt;p&gt;Some additional changes to the genetic algorithm were added:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generational&lt;/strong&gt;: a strain is evolved for 100 iterations before moving to the
next strain.  after 10 strains are evolved, they are all mutated at once and
the genetic algorithm is run on this &lt;em&gt;megastrain&lt;/em&gt; for 500 iterations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fertility&lt;/strong&gt;: In a given iteration, the higher scoring children have more
children. In this tuning, the top third get 3 copies of each mutation type, the
middle get 2 and the last get 1.&lt;/p&gt;

&lt;p&gt;In order to not completely fall into local maxima, two more additional features were added:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spawning&lt;/strong&gt;: Each iteration has an additional set of randomly spawned
children added into it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Charity&lt;/strong&gt;: From the losers of each iteration, a random 10 programs are
chosen for mutation and added into the next iteration.&lt;/p&gt;

&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;/h3&gt;

&lt;p&gt;Using python, this runs reasonably slowly so pypy was used. But even that is not enough,
so a few optimizations were added:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pre-emptively trim a program that doesn’t have any forward instructions&lt;/li&gt;
  &lt;li&gt;Detect loops and end early if we get stuck in an endless loop&lt;/li&gt;
  &lt;li&gt;Don’t run a program for more than 2000 instructions&lt;/li&gt;
  &lt;li&gt;Stop trying after 2 minutes and move on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Side Note: I wrote a brute force solver in c++ and pypy and surprisingly, the pypy was
comparable in performance with generating all possible permutations. This had
me wracking my head for a while - I still don’t understand what’s slow in the c++
version.&lt;/p&gt;

&lt;h3 id=&quot;a-better-sort-of-randomness&quot;&gt;A better sort of randomness&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Added on: February 4th&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Around 7500 solved puzzles, the solver started hitting a wall. Thinking about
what could be improved, a question I had was: “can we do better than pure
randomness when selecting instructions?”.  A program that has “write red”,
“write red”, “write red” several times in a row is not actually that useful.&lt;/p&gt;

&lt;p&gt;Wondering about how we can generate feasible programs and not just any program,
I realized we can use markov chains for picking the instruction to place in a
specific position.&lt;/p&gt;

&lt;p&gt;Using the solutions from previously solved puzzles, we can generate probability
distributions of which operations are likely to follow other operations. This
concentrates the solutions that are generated, allowing the solver to go
through more feasible programs in the same amount of time.&lt;/p&gt;

&lt;p&gt;To gauge the difference, I ran the solver on the same puzzle 50 times and looked
at the average solve time. With markov chains, the solve time averaged 4.7
seconds vs 7.3 seconds.&lt;/p&gt;

&lt;p&gt;Using markov chains has shown the ability to solve more puzzles, but there are
still at least a thousand unsolved puzzles. These puzzles tend to use stacks
and the current solver fitness function seems to be having difficulties with
them. A next area to explore is how to solve stack based puzzles in a better
way.&lt;/p&gt;

&lt;h3 id=&quot;solving-even-more-problems&quot;&gt;Solving even more problems&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Added on: February 10th&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I received an email asking me for the source of robozzle. The email writer
wanted a solver that could solve some pretty hard problems. After looking
at the problems and what robozlov had been failing on, it was
apparent that robozlov had difficulty with stack solutions.&lt;/p&gt;

&lt;p&gt;It took a little experimenting to come up with a fitness metric that would help
solve these problems, but after a couple days, it seems that one metric has
helped a little bit. Now the fitness function is a combination of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;stars collected / total stars&lt;/li&gt;
  &lt;li&gt;squares visited / total sum of squares&lt;/li&gt;
  &lt;li&gt;number of stack pops / total instructions executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new value, &lt;strong&gt;number of stack pops&lt;/strong&gt; is essentially: how often do we exit a
sub-routine. This was the best number I could come up with, but there might be
a better one. If we had chosen, &lt;em&gt;number of stack pushes&lt;/em&gt;, the solver would
prioritize endless loops. We need a mechanism to reward using the stack - hence
the stack pops.&lt;/p&gt;

&lt;p&gt;With this modified solver, we can now a solve a few hundred more puzzles, but
still haven’t been able to solve the originally requested puzzles.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;So how did the program do? After running it for ~3 days, it downloaded and
solved 65.5% of the available puzzles on robozzle for a total of 6937 solved
puzzles out of 10,579 total.&lt;/p&gt;

&lt;p&gt;The first run solved ~6300 puzzles. I noticed that there was some improvements
that could be made on loop detection and a second run yielded ~400 more solved
puzzles - some likely by random chance and some because of the modified loop
detection. A third run yielded ~200 more puzzles solved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jan 30th Update:&lt;/strong&gt; The solver is now sitting at 70.5% success rate, with 7471
solved puzzles. Robozlov is sitting at 9th rank.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feb 10th Update:&lt;/strong&gt; The solver is now at 74.4% success rate, with 7922 puzzles
solved. Robozlov is now sitting pretty at 5th rank&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/robozlov_board.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The scoreboard only counts puzzles that have a positive amount of likes&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;comparison&quot;&gt;Comparison&lt;/h3&gt;

&lt;p&gt;Multiple other people have written robozzle solvers, but the best I’ve seen is
&lt;a href=&quot;https://github.com/tasuki/zlej-rob&quot;&gt;zlejrob&lt;/a&gt; which has solved ~4500 puzzles as
of January 2023 and is in rank 26 or 27 on the leaderboard. Tasuki wrote up
their approach &lt;a href=&quot;https://blog.tasuki.org/explorations-in-ai-solving-robozzle/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other solvers I’ve seen are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/nicuveo/Zolver&quot;&gt;Zolver&lt;/a&gt;: a brute force solver&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://robai.blogs.losttech.software/&quot;&gt;RobAI&lt;/a&gt;: an ML based solver&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.ptitpoulpe.fr/files/projects/games/robozzle.py&quot;&gt;robozzle.py&lt;/a&gt;: another brute forcer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;how-could-it-be-improved&quot;&gt;How could it be improved?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Modify the genetic algorithm to favor shorter solutions - currently the solutions always use the
full puzzle length&lt;/li&gt;
  &lt;li&gt;Look at puzzles that weren’t solved well and see if there are any insights as to why&lt;/li&gt;
  &lt;li&gt;Currently, the evolution + generational iterations are hard-coded. It would be interesting
to determine the “momentum” of a strain and keep improving it until we hit a wall&lt;/li&gt;
  &lt;li&gt;Combine “similar” strains into one group: if we evolve a strain and it looks similar to a previous
strain, we can probably merge them&lt;/li&gt;
  &lt;li&gt;The solver tends to do poorly on solutions that have multiple functions of 10 instructions, these
seem to make it stumble&lt;/li&gt;
  &lt;li&gt;It’s not clear that the tile scoring function (distance from closest star) is the best scoring function for exploration. There could be a puzzle that requires moving away from the star first that this scoring would penalize.&lt;/li&gt;
  &lt;li&gt;Analyze the “genealogy” of solutions and compare the frequency of a solution arriving during the normal strain evolution and megastrain evolution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h3&gt;

&lt;p&gt;This was a fun exercise over the last 2 weeks - I’ve been pleasantly surprised
by the results. One thing that stuck out to me is how the terminology used
affected the approach. Once genetic algorithm was chosen, the types of
optimizations were influenced by the genetic metaphor. If I had chosen
simulated annealing or a different evolutionary algorithm, maybe a different
set of optimizations would have come out.&lt;/p&gt;

</description>
          <pubDate>Thu, 12 Jan 2023 00:00:00 -0800</pubDate>
          <link>https://oky.moe/robozlov/</link>
          <guid isPermaLink="true">https://oky.moe/robozlov/</guid>
          
          
          <category>code</category>
          
        </item>
      
    
      
        <item>
          <title>applications i use on gnu/linux</title>
          <description>&lt;p&gt;When setting up a new machine, I generally go through the same process: install
a minimal linux OS, then add my favored applications on top of it. In this
post, I’ll list the applications I tend to install and use. See &lt;a href=&quot;/my-history-with-linux&quot;&gt;this
post&lt;/a&gt; if you want to see my history of linux usage.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/desktop.png&quot;&gt;&lt;img src=&quot;/images/desktop.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;desktop&quot;&gt;Desktop&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Desktop Environment: &lt;a href=&quot;https://xfce.org/&quot;&gt;xfce4&lt;/a&gt;&lt;sup id=&quot;fnref:xfce4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:xfce4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;File Manager: &lt;a href=&quot;https://wiki.archlinux.org/title/thunar&quot;&gt;thunar&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Window Manager: &lt;a href=&quot;https://wiki.archlinux.org/title/xmonad&quot;&gt;xmonad&lt;/a&gt; (&lt;a href=&quot;https://github.com/okayzed/xmonad-config&quot;&gt;my config&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Top Panel: &lt;a href=&quot;https://wiki.archlinux.org/title/Xmobar&quot;&gt;xmobar&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Bottom Panel: &lt;a href=&quot;https://docs.xfce.org/xfce/xfce4-panel/start&quot;&gt;xfce4-panel&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Notifications: &lt;a href=&quot;https://wiki.archlinux.org/title/dunst&quot;&gt;dunst&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Quick Launcher: &lt;a href=&quot;https://wiki.archlinux.org/title/rofi&quot;&gt;rofi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;applications&quot;&gt;Applications&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Browser: firefox and sometimes chromium&lt;/li&gt;
  &lt;li&gt;Editor: &lt;a href=&quot;https://www.vim.org&quot;&gt;vim&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;File Manager: &lt;a href=&quot;https://wiki.archlinux.org/title/thunar&quot;&gt;thunar&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Rest Breaks: &lt;a href=&quot;https://workrave.org/&quot;&gt;workrave&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Audio Control: &lt;a href=&quot;https://wiki.archlinux.org/title/PulseAudio&quot;&gt;pavucontrol&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Bluetooth: &lt;a href=&quot;https://wiki.archlinux.org/title/bluetooth&quot;&gt;blueberry&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Networking: &lt;a href=&quot;https://wiki.archlinux.org/title/NetworkManager&quot;&gt;nm-applet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Movie Player: &lt;a href=&quot;https://wiki.archlinux.org/title/mpv&quot;&gt;mpv&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;File Sync: &lt;a href=&quot;https://wiki.archlinux.org/title/syncthing&quot;&gt;syncthing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;PDF Reader: &lt;a href=&quot;https://wiki.archlinux.org/title/zathura&quot;&gt;zathura&lt;/a&gt; with mupdf plugin (previously evince)&lt;/li&gt;
  &lt;li&gt;Voice chat: &lt;a href=&quot;https://wiki.archlinux.org/title/mumble&quot;&gt;mumble&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Screenshots: &lt;a href=&quot;https://docs.xfce.org/apps/xfce4-screenshooter/start&quot;&gt;xfce4-screenshooter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;development&quot;&gt;Development&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Compiler: gcc&lt;/li&gt;
  &lt;li&gt;Interpreter: python&lt;/li&gt;
  &lt;li&gt;Reverse Engineering: binary ninja, radare2&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;terminal-stuff&quot;&gt;Terminal Stuff&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Shell: bash&lt;/li&gt;
  &lt;li&gt;Terminal Manager: &lt;a href=&quot;https://github.com/tmux/tmux&quot;&gt;tmux&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Themes: &lt;a href=&quot;chriskempson.com/projects/base16/&quot;&gt;base16-theme-manager&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Terminal: xfce4-terminal&lt;/li&gt;
  &lt;li&gt;IRC/Chat: &lt;a href=&quot;https://wiki.archlinux.org/title/weechat&quot;&gt;Weechat&lt;/a&gt; + &lt;a href=&quot;https://wiki.archlinux.org/title/bitlbee&quot;&gt;Bitlbee&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;SSH: &lt;a href=&quot;https://wiki.archlinux.org/title/mosh&quot;&gt;mosh&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Syncing: &lt;a href=&quot;https://wiki.archlinux.org/title/rsync&quot;&gt;rsync&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;knowledge-management&quot;&gt;Knowledge Management&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Ebook library: &lt;a href=&quot;https://calibre-ebook.com/&quot;&gt;calibre&lt;/a&gt;&lt;sup id=&quot;fnref:calibre&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:calibre&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;PDF library: &lt;a href=&quot;https://zotero.org&quot;&gt;zotero&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Youtube: youtube-dl&lt;/li&gt;
  &lt;li&gt;Notes: filekasten&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;writing&quot;&gt;Writing&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Blog Engine: &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;jekyll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Markdown Language: &lt;a href=&quot;https://kramdown.gettalong.org/&quot;&gt;kramdown&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Doc converter: &lt;a href=&quot;https://pandoc.org&quot;&gt;pandoc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;misc&quot;&gt;Misc&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;xmodmap for setting caps lock to control key&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/milaq/XMousePasteBlock&quot;&gt;xmousepasteblock&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/fzf&quot;&gt;fzf: fuzzy file finder&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/rupa/z&quot;&gt;z: quick directory switching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;vim-plugins&quot;&gt;Vim Plugins&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/okayzed/dotvim/tree/master/bundle&quot;&gt;see this list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:xfce4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I use xfce4 because it’s somewhat lightweight and provides several session based functions I like: dbus communication, integration with printers, monitor management, etc. The applications I use from xfce4 are: xfce4-panel, xfce4-terminal, xfce4-session - but not xfce4-desktop, since I don’t need a desktop with icons. &lt;a href=&quot;#fnref:xfce4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:calibre&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I wish I had a better ebook manager, but this one is mostly fine &lt;a href=&quot;#fnref:calibre&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
          <pubDate>Sun, 26 Dec 2021 00:00:00 -0800</pubDate>
          <link>https://oky.moe/linux-applications/</link>
          <guid isPermaLink="true">https://oky.moe/linux-applications/</guid>
          
          
          <category>code</category>
          
        </item>
      
    
      
    
      
    
      
        <item>
          <title>on LD_PRELOAD and C++</title>
          <description>&lt;p&gt;LD_PRELOAD is a way to intercept system calls issued from glibc and interact
with them: modifying args, changing return values, completely exchanging
implementations, etc&lt;/p&gt;

&lt;p&gt;Some misc. things I learned about implementing preload hooks from C++:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/35330032/442652&quot;&gt;remember to wrap the calls with extern “C” to prevent function mangling from CPP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/16746166/using-cout-in-constructor-gives-segmentation-fault&quot;&gt;try not to use cout inside preload functions without initializing std::iostream&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;you can use c++ overloading instead of C var args, which is cool!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/35771395/why-doesnt-ld-preload-trick-catch-open-when-called-by-fopen&quot;&gt;LD_PRELOAD doesn’t necessarily cover all function invocations (f.e. system calls not invoked via glibc) - ptrace does a better job here&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;if you get undefined symbol errors during linking, it could be that you compiled with gcc instead of g++!&lt;/li&gt;
  &lt;li&gt;if your hooks aren’t being run, try implementing the 64 version: i.e. open64() vs open()&lt;/li&gt;
  &lt;li&gt;openat() may or may not be a systemcall - it likely calls open() or open64()&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;an-example-preload-in-cpy&quot;&gt;An example preload in CPY&lt;/h3&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;dlfcn.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// we use extern C to prevent symbol mangling for usage in LD_PRELOAD&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_libhook_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_libhook_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;INIT HOOK&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;func_open&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dlsym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RTLD_NEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;open&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;OPENING PATH %s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
          <pubDate>Thu, 23 Jul 2020 00:00:00 -0700</pubDate>
          <link>https://oky.moe/ld-preload-cpp/</link>
          <guid isPermaLink="true">https://oky.moe/ld-preload-cpp/</guid>
          
          
          <category>code</category>
          
        </item>
      
    
      
    
      
        <item>
          <title>My gnu/linux desktop setup</title>
          <description>&lt;h3 id=&quot;redhat-years-2002---2003&quot;&gt;Redhat years (2002 - 2003)&lt;/h3&gt;

&lt;p&gt;The first distro I used was Mandrake Linux and then Redhat linux.  When I first
intalled these distros, I had to use installation CDs and printed manuals to
get up and running.  In those days, wifi often required special drivers and we
had to compile kernel modules to get the network working. Good luck if you
wanted hardware graphics card support (AMD Radeon, I’m looking at you)&lt;/p&gt;

&lt;p&gt;I used Gnome as my desktop manager, but I liked to explore new packages and
bleeding edge features. I was new to gnu/linux at this point and mostly had no
idea what was going on - I slowly learned that /etc/ contained configs, /home/
was user data and /usr/ was for packages installed on the system. I had no idea
that packages could be compiled against different libraries and would often try
to install packages I found using an RPM search website only to find out that I
was missing dependencies or had a different version of the library installed.&lt;/p&gt;

&lt;h3 id=&quot;archlinux-2003---2007&quot;&gt;ArchLinux (2003 - 2007)&lt;/h3&gt;

&lt;p&gt;After installing some bad packages and messing up my package tree a few times,
I eventually realized that the .rpm package format was not for me and moved to
ArchLinux. From 2003 - 2007, I used ArchLinux - especially since I had enough
time on my hands to fix broken installs.  On Arch, I tried out different WMs,
including Xfce, WindowMaker and Fluxbox.  Every few weeks I would customize my
desktop, fiddling with backgrounds, menus and organization.&lt;/p&gt;

&lt;p&gt;My favorite feature of Arch was the PKGBUILDs and how easy it was for the
community to share packages. Having a forum of dedicated bleeding edge users
was great for exploring and trying out new things.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/harthub.png&quot;&gt;&lt;img src=&quot;/images/harthub.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of my favorite programs from this time were GkrellM, Conky, MPD and XMMS.
I used gaim (later renamed to pidgin) for messaging and hexchat for IRC.&lt;/p&gt;

&lt;h3 id=&quot;the-switch-to-ubuntu-2007&quot;&gt;The switch to Ubuntu (2007)&lt;/h3&gt;

&lt;p&gt;In 2007, I started working full time and realized I didn’t have time to mess
around with broken upgrades and moved to Ubuntu LTS. The idea was that I could
install a mostly default system and not have to worry about upgrades breaking
things for me.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/oldketchup.png&quot;&gt;&lt;img src=&quot;/images/oldketchup.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was mostly accurate - but at some point SystemD started taking over more
and more subsystems. With each upgrade, I now had to worry that some new
SystemD feature would be broken or require a config workaround. Still - I
thought this was better than bleeding edge breaks.  Now (in 2019), SystemD
mostly doesn’t bother my life, but I am still apprehensive when I do a
dist-upgrade.&lt;/p&gt;

&lt;h3 id=&quot;the-switch-to-mint-2020&quot;&gt;The switch to Mint (2020)&lt;/h3&gt;

&lt;p&gt;Ubuntu announced they were going with snap packages for popular packages, so I
started searching for my next setup. The choice was mostly between arch or
Mint, but I decided to go with Mint for now.&lt;sup id=&quot;fnref:arch&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:arch&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; So far so good, it’s
similar to Ubuntu in most ways.&lt;/p&gt;

&lt;h3 id=&quot;the-current-setup-2009---now&quot;&gt;The current setup (2009 - Now)&lt;/h3&gt;

&lt;p&gt;In 2009, I started thinking about how to eliminate the mouse from my life (&lt;a href=&quot;/mousekips&quot;&gt;see
my post on mousekips&lt;/a&gt;) and eventually moved to using Xmonad as my window
manager with Xfce4 as my desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/xmonad_black.png&quot;&gt;&lt;img src=&quot;/images/xmonad_black.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I like about xmonad is that I can do most of my window management tasks
using the keyboard and dual monitors are well supported.  There’s a simple
timelessness to a minimal desktop: my rot window is all black and there’s no
window decorations for minimizing, maximizing or closing windows.&lt;/p&gt;

&lt;p&gt;My philosophy for how I use my desktop is simple: each workspace usually has
one window maximized on it. This is so that I can focus on one task at a time.
For web dev, I use dual pane mode: one pane is the dev tools, the other is the
browser.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/xmonad_terminal.png&quot;&gt;&lt;img src=&quot;/images/xmonad_terminal.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;work-computers-2019---now&quot;&gt;Work Computers (2019 - Now)&lt;/h3&gt;

&lt;p&gt;At work, I use fedora, but I still use the same setup as my home machine:
xfce4+xmonad. I’ve gotten pretty good at installing and configuring a system
at this point: it only takes a couple hours to bring up a fresh install
with all my regularly used applications.&lt;/p&gt;

&lt;h3 id=&quot;the-future-now---&quot;&gt;The future (Now - ???)&lt;/h3&gt;

&lt;p&gt;I’ve spent 10+ years with xmonad, because of how well it works for me. I’ve
tried switching away every few years and always end up returning.&lt;/p&gt;

&lt;p&gt;The main downside of xmonad for me is that the configuration is in Haskell. As
someone who doesn’t know Haskell (&lt;em&gt;gasp&lt;/em&gt;), configuring xmonad is hit or miss.
I’ve been setting up AwesomeWM which is configured in Lua, but haven’t managed
to get it exactly the same as my xmonad setup. There are small bumps and the
defaults don’t seem to work as well as I want. I’ve also heard good things
about i3, but haven’t had a chance to try it out.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:arch&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I think it was because the cross compilers for arm in arch requiring a custom AUR build &lt;a href=&quot;#fnref:arch&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
          <pubDate>Sun, 18 Aug 2019 00:00:00 -0700</pubDate>
          <link>https://oky.moe/my-history-with-linux/</link>
          <guid isPermaLink="true">https://oky.moe/my-history-with-linux/</guid>
          
          
          <category>code</category>
          
        </item>
      
    
  </channel>
</rss>
