aboutsummaryrefslogtreecommitdiff
path: root/public/trying-to-build-a-new-kind-of-terminal-emulator.html
diff options
context:
space:
mode:
Diffstat (limited to 'public/trying-to-build-a-new-kind-of-terminal-emulator.html')
-rwxr-xr-xpublic/trying-to-build-a-new-kind-of-terminal-emulator.html224
1 files changed, 0 insertions, 224 deletions
diff --git a/public/trying-to-build-a-new-kind-of-terminal-emulator.html b/public/trying-to-build-a-new-kind-of-terminal-emulator.html
deleted file mode 100755
index 6b42a0f..0000000
--- a/public/trying-to-build-a-new-kind-of-terminal-emulator.html
+++ /dev/null
@@ -1,224 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Trying to build a New kind of terminal emulator for the modern age</title><meta name=description content="Over the past few weeks, I have been really thinking about terminal emulators,how we interact with computers, the separation of text-based programs and GUIones."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Trying to build a New kind of terminal emulator for the modern age</h1><p><cap>post</cap>, Jan 26, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Over the past few weeks, I have been really thinking about terminal emulators,
10how we interact with computers, the separation of text-based programs and GUI
11ones. To be perfectly honest, I got pissed off one evening when I was cleaning
12up files on my computer. Normally, I go into console and do <code>ncdu</code> and check
13where the junk is. Then I start deleting stuff. Without any discrimination,
14usually. But when it comes to screenshots, I have learned that it's good to keep
15them somewhere near if I need to refer to something that I was doing. I am an
16avid screenshot taker. So at that point I checked Pictures folder and also did a
17basic search <code>find . -type f -name "*.jpg"</code> for all the JPEG files in my home
18directory and immediately got pissed off. Why can’t I see thumbnails in my
19terminal? I know why, but why in the year of 2022 this is still a problem. I am
20used to traversing my disk via terminal. I am faster, and I am more comfortable
21this way. But when it comes to visualization, I then need to revert to GUI
22applications and again find the same file to see it. I know that programs like
23<code>feh</code> and <code>sxiv</code> are available, but I would just like to see the preview. Like
24<a href=https://jupyter.org/>Jupyter notebook</a> or something similar. Just having it
25inline. Part of a result.<p>It also didn’t help that I was spending some time with the <a href=https://plan9.io/plan9/>Plan
269</a> Operating system. More specifically
27<a href=http://9front.org/>9FRONT</a>. The way that <a href=http://acme.cat-v.org/>ACME editor</a>
28handles text editing is just wonderful. Different and fresh somehow, even though
29it’s super old.<p>So, I went on a lookout for an interesting way of visualizing results of some
30query. I found these applications to be outstanding examples of how not to be a
31captive of a predetermined way of doing things.<ul><li><a href=https://www.wolfram.com/mathematica/>Wolfram Mathematica</a><li><a href=https://jupyter.org/>Jupyter notebooks</a><li><a href=http://www.9front.org>Plan 9 / 9FRONT</a><li><a href=https://templeos.org/>Temple OS</a><li><a href=https://www.gnu.org/software/emacs/>Emacs</a></ul><p>My idea is not as out there as ACME is, but it is a spin on the terminal
32emulators. I like the modes that Vi/Vim provides you with. I like the way the
33Emacs does its own <code>M-x</code> <code>M-c</code>. Furthermore, I really like how Mathematica and
34Jupyter present the data in a free flowing form. And I love how Temple OS is
35basically a C interpreter on some level.<blockquote><p><strong>Note:</strong> This is part 1 of the journey. Nowhere finished yet. I am just
36tinkering with this at the moment. This whole thing can easily spectacularly
37fail.</blockquote><p>So I started. I knew that I wanted to have the couple of modes, but I didn’t
38like the repetition of keystrokes, so the only option was to have some sort of
39toggle and indicate to the user that they are in a special mode. Like Vi does
40for Normal and Visual mode.<p>These modes would for the first version be:<ul><li><em>Preview mode</em> (toggle with Ctrl + P)<ul><li>When this mode would be enabled, the <code>ls</code> command would try to find images
41from the results and display thumbnails from them in the terminal itself.
42No ASCII art. Proper images. In a grid!</ul><li><em>Detach mode</em> (toggle with Ctrl + D)<ul><li>When this mode would be enabled, every command would open a new window
43and execute that command in it. This would be useful for starting <code>htop</code>
44in a separate window.</ul></ul><p>The reason for having these modes togglable is to not ask for previews every
45time. You enable a mode and until you disable it, it behaves that way. Purely
46out of ergonomic reasons.<p>I would like to treat every terminal I open as a session mentally. When I start
47using the terminal, I start digging deeper into the issue I am trying to
48resolve. And while I am doing this, I would like to open detached windows
49etc. A lot of these things can be done easily with something like
50<a href=https://i3wm.org/>i3</a>, but also that pull you out of the context of what you
51were doing. I would like to orchestrate everything from one single point.<p>In planning for this project, I knew that I would need to use a language like C
52and a library such as <a href=https://www.libsdl.org/>SDL2</a> in order to achieve the
53desired results. I had considered other options, but ultimately determined that
54<a href=https://www.libsdl.org/>SDL2</a> was the best fit based on its capabilities and
55reputation in the programming community.<p>At first, I thought the idea of a hardware accelerated terminal was a bit of a
56joke. It seemed like such a niche and unnecessary feature, especially given the
57fact that terminal emulators have been around for decades and have always relied
58on software rendering. But to be fair, <a href=https://alacritty.org/>Alacritty</a> is
59doing the same thing. Well, they are doing a remarkable job at it.<p>So, I embarked on a journey. Everything has to start somewhere. For me, it
60started with creating a window! It has to start somewhere. 🙂<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>// Oh, Hi Mark!
61</span></span></span><span style=display:flex><span><span style=color:green>// Create the window, obviously.
62</span></span></span><span style=display:flex><span><span style=color:green></span>SDL_Window *window = SDL_CreateWindow(
63</span></span><span style=display:flex><span> WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
64</span></span><span style=display:flex><span> WINDOW_WIDTH, WINDOW_HEIGHT,
65</span></span><span style=display:flex><span> SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
66</span></span></code></pre><p>I continued like this to get some text displayed on the screen.<p>I noted that
67<a href=https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_Solid><code>TTF_RenderText_Solid</code></a>
68rendered text really poorly. There were no antialiasing at all. In my wisdom, I
69never checked the documentation. Well, that was a fail. To uneducated like me:
70<code>TTF_RenderText_Solid</code> renders Latin1 text at fast quality to a new 8-bit
71surface. So, that's why the texts looked like shit. No wonder.<p>Remarks on <code>TTF_RenderText_Solid</code>: This function will allocate a new 8-bit,
72palettized surface. The surface's 0 pixel will be the colorkey, giving a
73transparent background. The 1 pixel will be set to the text color.<p>After I replaced it with
74<a href=https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_LCD><code>TTF_RenderText_LCD</code></a> which
75renders Latin1 text at LCD subpixel quality to a new ARGB surface, the text
76started looking good. Really make sure you read the documentation. It’s actually
77good. As a side note, you can find all the documentation regarding <a href=https://wiki.libsdl.org/>SDL2 on
78their Wiki</a>.<p>After that was done, I started working on displaying other things like <code>Preview</code>
79and <code>Detach</code> modes. This wasn’t really that hard. In SDL2 you can check all the
80available events with <code>while (SDL_PollEvent(&amp;event) > 0)</code> and have a bunch of
81switch statements to determine which key is currently being pressed. More about
82keys, <a href=https://documentation.help/SDL/sdlkey.html>SDLKey</a> and mroe about
83pooling the events on
84<a href=https://documentation.help/SDL/sdlpollevent.html>SDL_PollEvent</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>while</span> (SDL_PollEvent(&amp;event) &gt; 0)
85</span></span><span style=display:flex><span>{
86</span></span><span style=display:flex><span> <span style=color:#00f>switch</span> (event.type)
87</span></span><span style=display:flex><span> {
88</span></span><span style=display:flex><span> <span style=color:#00f>case</span> SDL_QUIT:
89</span></span><span style=display:flex><span> running = false;
90</span></span><span style=display:flex><span> <span style=color:#00f>break</span>;
91</span></span><span style=display:flex><span>
92</span></span><span style=display:flex><span> <span style=color:#00f>case</span> SDL_TEXTINPUT:
93</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (!meta_key_pressed)
94</span></span><span style=display:flex><span> {
95</span></span><span style=display:flex><span> strncat(input_prompt_text, event.text.text, 1);
96</span></span><span style=display:flex><span> update_input_prompt = true;
97</span></span><span style=display:flex><span> }
98</span></span><span style=display:flex><span> <span style=color:#00f>break</span>;
99</span></span><span style=display:flex><span> }
100</span></span><span style=display:flex><span>}
101</span></span></code></pre><p>After that was somewhat working correctly, I started creating a struct that
102would hold all the commands and results and I call them Cells. Yes, I stole that
103naming idea from Jupyter.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>typedef</span> <span style=color:#00f>struct</span>
104</span></span><span style=display:flex><span>{
105</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> *command;
106</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> *result;
107</span></span><span style=display:flex><span> SDL_Surface *surface;
108</span></span><span style=display:flex><span> SDL_Texture *texture;
109</span></span><span style=display:flex><span> SDL_Rect rect;
110</span></span><span style=display:flex><span>} Cell;
111</span></span></code></pre><p>I am at a place now where I am starting to implement scrolling. This will for
112sure be fun to code. Memory management in C is super easy. 😂<p>I have also added a simple <a href=https://en.wikipedia.org/wiki/INI_file>INI file like
113configuration</a> support. It is done in an
114<a href=https://github.com/nothings/stb/blob/master/docs/stb_howto.txt>STB style of
115header</a> and maps
116to specific options supported by the terminal. It is not universal, and the code
117below demonstrates how I will use it in the future.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#ifndef CONFIG_H
118</span></span></span><span style=display:flex><span><span style=color:#00f>#define CONFIG_H
119</span></span></span><span style=display:flex><span><span style=color:#00f></span>
120</span></span><span style=display:flex><span><span style=color:green>/*
121</span></span></span><span style=display:flex><span><span style=color:green># This is a comment
122</span></span></span><span style=display:flex><span><span style=color:green>
123</span></span></span><span style=display:flex><span><span style=color:green># This is the first configuration option
124</span></span></span><span style=display:flex><span><span style=color:green>dettach=value11111
125</span></span></span><span style=display:flex><span><span style=color:green>
126</span></span></span><span style=display:flex><span><span style=color:green># This is the second configuration option
127</span></span></span><span style=display:flex><span><span style=color:green>preview=value22222
128</span></span></span><span style=display:flex><span><span style=color:green>
129</span></span></span><span style=display:flex><span><span style=color:green># This is the third configuration option
130</span></span></span><span style=display:flex><span><span style=color:green>debug=value33333
131</span></span></span><span style=display:flex><span><span style=color:green>*/</span>
132</span></span><span style=display:flex><span>
133</span></span><span style=display:flex><span><span style=color:green>// Define a struct to hold the configuration options
134</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>typedef</span> <span style=color:#00f>struct</span>
135</span></span><span style=display:flex><span>{
136</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> dettach[256];
137</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> preview[256];
138</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> debug[256];
139</span></span><span style=display:flex><span>} Config;
140</span></span><span style=display:flex><span>
141</span></span><span style=display:flex><span><span style=color:green>// Read the configuration file and return the options as a struct
142</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>extern</span> Config read_config_file(<span style=color:#00f>const</span> <span style=color:#2b91af>char</span> *filename)
143</span></span><span style=display:flex><span>{
144</span></span><span style=display:flex><span> <span style=color:green>// Create a struct to hold the configuration options
145</span></span></span><span style=display:flex><span><span style=color:green></span> Config config = {0};
146</span></span><span style=display:flex><span>
147</span></span><span style=display:flex><span> <span style=color:green>// Open the configuration file
148</span></span></span><span style=display:flex><span><span style=color:green></span> FILE *file = fopen(filename, <span style=color:#a31515>&#34;r&#34;</span>);
149</span></span><span style=display:flex><span>
150</span></span><span style=display:flex><span> <span style=color:green>// Read each line from the file
151</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#2b91af>char</span> line[256];
152</span></span><span style=display:flex><span> <span style=color:#00f>while</span> (fgets(line, <span style=color:#00f>sizeof</span>(line), file))
153</span></span><span style=display:flex><span> {
154</span></span><span style=display:flex><span> <span style=color:green>// Check if this line is a comment or empty
155</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>if</span> (line[0] == <span style=color:#a31515>&#39;#&#39;</span> || line[0] == <span style=color:#a31515>&#39;\n&#39;</span>)
156</span></span><span style=display:flex><span> <span style=color:#00f>continue</span>;
157</span></span><span style=display:flex><span>
158</span></span><span style=display:flex><span> <span style=color:green>// Parse the line to get the option and value
159</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#2b91af>char</span> option[128], value[128];
160</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (sscanf(line, <span style=color:#a31515>&#34;%[^=]=%s&#34;</span>, option, value) != 2)
161</span></span><span style=display:flex><span> <span style=color:#00f>continue</span>;
162</span></span><span style=display:flex><span>
163</span></span><span style=display:flex><span> <span style=color:green>// Set the value of the appropriate option in the config struct
164</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;dettach&#34;</span>) == 0)
165</span></span><span style=display:flex><span> {
166</span></span><span style=display:flex><span> strncpy(config.option1, value, <span style=color:#00f>sizeof</span>(config.option1));
167</span></span><span style=display:flex><span> }
168</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;preview&#34;</span>) == 0)
169</span></span><span style=display:flex><span> {
170</span></span><span style=display:flex><span> strncpy(config.option2, value, <span style=color:#00f>sizeof</span>(config.option2));
171</span></span><span style=display:flex><span> }
172</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;debug&#34;</span>) == 0)
173</span></span><span style=display:flex><span> {
174</span></span><span style=display:flex><span> strncpy(config.option3, value, <span style=color:#00f>sizeof</span>(config.option3));
175</span></span><span style=display:flex><span> }
176</span></span><span style=display:flex><span> }
177</span></span><span style=display:flex><span>
178</span></span><span style=display:flex><span> <span style=color:green>// Close the configuration file
179</span></span></span><span style=display:flex><span><span style=color:green></span> fclose(file);
180</span></span><span style=display:flex><span>
181</span></span><span style=display:flex><span> <span style=color:green>// Return the configuration options
182</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>return</span> config;
183</span></span><span style=display:flex><span>}
184</span></span><span style=display:flex><span>
185</span></span><span style=display:flex><span><span style=color:#00f>#endif
186</span></span></span></code></pre><p>This is as far as I managed to get for now. I have a daily job and this
187prohibits me to work on these things full time. But I should probably get back
188and finish this. At least have a simple version working out, so I can start
189testing it on my machines. Fingers crossed. 🕵️‍♂️</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
190a lock on a Linux NFS server, which turned
191out to be specific to NFS v3 (which I really should have seen coming,
192since it involved NLM and lockd). Finding the NFS v4 client that
193owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
194and Bradley Kuhn, are interacting on the OSI's license-discuss
195list where the're doing
196bad computer history and insisting that a guy Larry Rosen
197coincidentally interviewed for a book years ago is clearly the origin of
198somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
199i2c, plan9
200Another month, another file system.
201Well, if you can’t fix it in software, fix it in hardware (looking at
202you, bme680, we’re not
203done yet). The show must go on, as they say, and I would like my
204experiments to go on.
205So a “new” addition to the environmental sensor family connected to
206the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
207this mortal coil, we are endowed with self-awareness, agency, and free will.
208Each of the 8 billion members of this human race represents a unique person, a
209unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
210My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2111.0 has been released:
212wifi_da-1.0.sit
213(StuffIt 3 archive)
214SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
215This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
216classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
217In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
218Design Goals
219I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
220at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
221catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
222specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
223 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
224 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file