<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Z Space Blog - Software</title><link href="https://zlg.space/blog/" rel="alternate"/><link href="https://zlg.space/blog/feeds/c/software.atom.xml" rel="self"/><id>https://zlg.space/blog/</id><updated>2025-09-25T00:46:00-07:00</updated><entry><title>Vim Author Bram Moolenaar Has Died</title><link href="https://zlg.space/blog/vim-author-bram-moolenaar-has-died.html" rel="alternate"/><published>2023-08-05T12:38:00-07:00</published><updated>2023-08-05T12:38:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2023-08-05:/blog/vim-author-bram-moolenaar-has-died.html</id><summary type="html">&lt;p&gt;I woke up to a &lt;a href="https://lobste.rs/s/yrlb5m/message_from_family_bram_moolenaar_he"&gt;huge&lt;/a&gt; &lt;a href="https://news.slashdot.org/story/23/08/05/1632219/vims-creator-bram-moolenaar-dies-at-age-62"&gt;gut&lt;/a&gt; &lt;a href="https://news.ycombinator.com/item?id=37011324"&gt;punch&lt;/a&gt; this
morning: &lt;a href="https://groups.google.com/g/vim_announce/c/tWahca9zkt4"&gt;Bram Moolenaar, legendary author of the Vim text editor, has passed
away&lt;/a&gt;. Given the occasion, I want to express some thoughts
regarding both Bram and his software. Without his work, I'm not sure I would be
the same person.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I woke up to a &lt;a href="https://lobste.rs/s/yrlb5m/message_from_family_bram_moolenaar_he"&gt;huge&lt;/a&gt; &lt;a href="https://news.slashdot.org/story/23/08/05/1632219/vims-creator-bram-moolenaar-dies-at-age-62"&gt;gut&lt;/a&gt; &lt;a href="https://news.ycombinator.com/item?id=37011324"&gt;punch&lt;/a&gt; this
morning: &lt;a href="https://groups.google.com/g/vim_announce/c/tWahca9zkt4"&gt;Bram Moolenaar, legendary author of the Vim text editor, has passed
away&lt;/a&gt;. Given the occasion, I want to express some thoughts
regarding both Bram and his software. Without his work, I'm not sure I would be
the same person.&lt;/p&gt;


&lt;h1&gt;How I found Vim&lt;/h1&gt;
&lt;p&gt;On a wintry Wisconsin night in 2004, I was looking for better, more customizable
software. I was a teenager, learning about alternative OSes and losing patience
with Windows every passing day. I had started getting more serious about
learning web development, and began trying different text editors, to see what
was to my taste. As we all know, Notepad on Windows is &lt;em&gt;NOT&lt;/em&gt; sufficient for 
programming.&lt;/p&gt;
&lt;p&gt;On this path of discovering text editors, I stumbled across all sorts of things,
from UltraEdit to metapad, Notepad++, gedit, AceHTML, Emacs, and eventually I
found this free software called "vim", but it came with some newbie-friendly
settings, called &lt;a href="https://cream.sourceforge.net/"&gt;Cream&lt;/a&gt;. (I was surprised to see it's still around!) One
thing that stood out to me about Vim, at the time, was the fact I didn't have
to enter some weird licensing scheme. I didn't have to pay to unlock features,
and the big thing was -- if I wanted to help, I could donate to a charity that
actually helped people! That stuck with me, morally. "Huh, all these companies
are making software for profit, but this guy from Europe just wants me to help
some less fortunate people. That's awesome."&lt;/p&gt;
&lt;p&gt;I would not realize it until years later, but discovering Vim was a key step in
my journey to libre software and GNU/Linux. Had I not been looking for a free,
customizable text editor to do what I wanted, it may have delayed or slowed my
introduction to that world.&lt;/p&gt;
&lt;h1&gt;How I Use Vim Today&lt;/h1&gt;
&lt;p&gt;These days, I keep a small group of plugins (mostly things like &lt;code&gt;fugitive&lt;/code&gt;,
&lt;code&gt;tabular&lt;/code&gt;, &lt;code&gt;sparkup&lt;/code&gt;, and some syntax stuff), a hefty &lt;code&gt;vimrc&lt;/code&gt; with keyboard
layout switching capabilities, and there's almost always a Vim process open on
my machines. It earned a place as my favorite piece of software when I learned
how easy it is to extend its behavior. No other piece of software evolves &lt;em&gt;with&lt;/em&gt;
me and my skill level like Vim does.&lt;/p&gt;
&lt;p&gt;I love Vim's documentation system the most, I think. If there's anything I don't 
know about Vim, I can consult &lt;code&gt;:help&lt;/code&gt; and get answers &lt;em&gt;immediately&lt;/em&gt;. For 
anything else, there is a broad community of fellow &lt;em&gt;text-heads&lt;/em&gt; out there, who 
might even have saved a fricken macro for the task you're trying to achieve.&lt;/p&gt;
&lt;p&gt;Each time I learn something new about Vim, I feel like I've unlocked a new 
ability, or added a new text wrangling tool to my belt. This, in turn, improves 
my ability to manipulate text and makes the editing experience that much better.&lt;/p&gt;
&lt;h1&gt;The Future of Vim&lt;/h1&gt;
&lt;p&gt;It seems that Bram had tapped a successor, in some way, before he died, but
the state of things with the Vim project seem to indicate his death was not
&lt;em&gt;expected&lt;/em&gt;, per se, though he had been ill for a few months prior to his death.
It is sad to see another one of the "original breed" of FOSS hackers pass on.
It stands as a reminder of how little time we really have on this rock, and the
importance of choosing goals that one can look back on with pride. I hope that
the new primary author and maintainer, Christian Brabandt, leads the project
with the same core values that Bram did. &lt;a href="https://groups.google.com/g/vim_dev/c/6_yWxGhB_8I/m/ibserACYBAAJ"&gt;Christian expresses his thoughts in 
the Google Groups thread.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Vim is the reason I discovered the Free Software movement. It's the software
that I use most in my day-to-day computing. How strange, that a journey for a
good text editor led to me discovering an entire social movement of hackers that
I still hover around to this day, nearly 20 years later. Thank you, Bram, for
bringing joy to my computing and rewarding every new morsel of knowledge I gain
about this beautiful tool.&lt;/p&gt;
&lt;p&gt;I have nothing but condolences for the Moolenaar family in their time of 
grieving. I hope their hearts are made lighter by the worldwide celebration 
of Bram's wonderful work, and the many testimonies people are publishing today 
which show how influential he was. We are all privileged to have received his 
work.&lt;/p&gt;
&lt;p&gt;Please consider donating to &lt;a href="http://iccf.nl/news.html"&gt;ICCF Holland&lt;/a&gt; if you wish to leave a token of
appreciation for Bram. It's what he would ask for.&lt;/p&gt;</content><category term="Software"/><category term="Software"/><category term="Vim"/><category term="Libre Software"/><category term="Major Events"/></entry><entry><title>Why I learned C "Category-0" Style</title><link href="https://zlg.space/blog/why-i-learned-c-category-0-style.html" rel="alternate"/><published>2023-03-16T20:02:00-07:00</published><updated>2023-03-16T20:02:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2023-03-16:/blog/why-i-learned-c-category-0-style.html</id><summary type="html">&lt;p&gt;I've been asked a few times over the years why I chose to learn C with the
colloquially-known "K&amp;amp;R C Bible", and specifically the &lt;a href="https://clc-wiki.net/wiki/K%26R2_solutions:Ancillary:Category_numbers"&gt;&lt;em&gt;Category-0&lt;/em&gt;&lt;/a&gt;
style, coined on USENET back in the day.&lt;/p&gt;
&lt;p&gt;For those unfamiliar, I'm talking about &lt;em&gt;The C Programming Language, 2nd Ed.&lt;/em&gt;,
by Brian Kernighan and Dennis Ritchie, the creators of the language. In it are
a series of exercises that the reader can work on to build their knowledge of
C through actually building something with it. On &lt;code&gt;comp.lang.c&lt;/code&gt;, people would
share their solutions to exercises in this book. After a while, they coined
different categories of solutions, to refer to their robustness and complexity.&lt;/p&gt;
&lt;p&gt;Category-0 is solving each exercise &lt;em&gt;using only the knowledge the book gives 
you, up to that point&lt;/em&gt;. In other words, it's to approach it as a complete newbie 
and see what you can put together using only the stuff you've learned in the 
book.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I've been asked a few times over the years why I chose to learn C with the
colloquially-known "K&amp;amp;R C Bible", and specifically the &lt;a href="https://clc-wiki.net/wiki/K%26R2_solutions:Ancillary:Category_numbers"&gt;&lt;em&gt;Category-0&lt;/em&gt;&lt;/a&gt;
style, coined on USENET back in the day.&lt;/p&gt;
&lt;p&gt;For those unfamiliar, I'm talking about &lt;em&gt;The C Programming Language, 2nd Ed.&lt;/em&gt;,
by Brian Kernighan and Dennis Ritchie, the creators of the language. In it are
a series of exercises that the reader can work on to build their knowledge of
C through actually building something with it. On &lt;code&gt;comp.lang.c&lt;/code&gt;, people would
share their solutions to exercises in this book. After a while, they coined
different categories of solutions, to refer to their robustness and complexity.&lt;/p&gt;
&lt;p&gt;Category-0 is solving each exercise &lt;em&gt;using only the knowledge the book gives 
you, up to that point&lt;/em&gt;. In other words, it's to approach it as a complete newbie 
and see what you can put together using only the stuff you've learned in the 
book.&lt;/p&gt;


&lt;p&gt;I had considerable difficulty learning C at first, due mostly to its 
similarities to C++, the challenge of finding good advice and practice, etc. I 
settled on the K&amp;amp;R because it was written by the original language authors. By 
choosing my reference on that criteria, I was certain to find a book that was 
more accurate than most, at minimum.&lt;/p&gt;
&lt;p&gt;After buying my copy and eventually discovering the
&lt;a href="https://clc-wiki.net/wiki/"&gt;clc-wiki&lt;/a&gt;, I started grinding out &lt;a href="https://git.zlg.space/knr"&gt;my own K&amp;amp;R
solutions&lt;/a&gt;. As you can see via the commit log on the
repository, it was a very slow advancement due to real life interfering. But I
did eventually complete it, so that's cool, right?&lt;/p&gt;
&lt;p&gt;Similarly, I have a copy of &lt;em&gt;Programming in Lua&lt;/em&gt;, by Roberto Ierusalimschy, one
of the language's authors, and it's also a wonderful resource in teaching me
Lua. I've heard Stroustrup's C++ books are great for learning. I would buy a
similar reference for Python by Guido van Rossum, but Python is a large beast
that evolves quickly via PEPs and its online docs are superb, so I'm not sure 
what the value of it would be.&lt;/p&gt;
&lt;p&gt;If you're into C, feel free to give it a look. Patches and constructive feedback
are both welcome. There are plans to make a "modern C standard" version of the 
solutions as well, to illustrate the difference between "good code for learning" 
and "the way you should actually build this".&lt;/p&gt;</content><category term="Software"/><category term="C"/><category term="Category-0"/><category term="Programming"/></entry><entry><title>A Brief History of Web Versions</title><link href="https://zlg.space/blog/a-brief-history-of-web-versions.html" rel="alternate"/><published>2022-04-25T00:00:00-07:00</published><updated>2022-12-11T00:00:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2022-04-25:/blog/a-brief-history-of-web-versions.html</id><summary type="html">&lt;p&gt;Ever since Mark Zuckerburg pitched the Metaverse, the "Web 3.0" buzzword blew
up, describing a "Web" that is backed by cryptocurrency-like ledgers. Proof of
work, proof of stake, etc. NFTs (Non-Fungible Tokens) are also involved in a
scene like this.&lt;/p&gt;
&lt;p&gt;What in this picture is an evolution of existing Web technology? How does this
enhance the state of hypertext? To me, this is Meta's vision for their next Web
product. It is not a new version of an existing, open platform. It has nothing
to offer me as a programmer, gamer, writer, or server admin. It seems to be the
mixture of NFT scamming, VR, and botnet. It looks like an addiction chamber
for whales.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Ever since Mark Zuckerburg pitched the Metaverse, the "Web 3.0" buzzword blew
up, describing a "Web" that is backed by cryptocurrency-like ledgers. Proof of
work, proof of stake, etc. NFTs (Non-Fungible Tokens) are also involved in a
scene like this.&lt;/p&gt;
&lt;p&gt;What in this picture is an evolution of existing Web technology? How does this
enhance the state of hypertext? To me, this is Meta's vision for their next Web
product. It is not a new version of an existing, open platform. It has nothing
to offer me as a programmer, gamer, writer, or server admin. It seems to be the
mixture of NFT scamming, VR, and botnet. It looks like an addiction chamber
for whales.&lt;/p&gt;


&lt;p&gt;By "whales", I'm referring to customers who invest a &lt;em&gt;ton&lt;/em&gt; into their
entertainment, seemingly impulsively. It has led to moral questions in society
over "dark patterns", or methods of design which aim to keep the user engaged
and, in this case, paying for more microtransactions. These people will spend
literally thousands of dollars on mobile games. Many developers of this sort
of dark-patterned tech offer the software for free, with a few hooks like free
items to get started with. Then, once you're out of items, you find you can only
get them with real money, or spend time to grind it out. Whales are, in a sense,
people with poor impulse control unable to get out of the dopamine loop.&lt;/p&gt;
&lt;p&gt;Is it moral to allow a company to design their software in a way to take
advantage of vulnerable people? That's what I think of when I think of
metaverses and NFTs.&lt;/p&gt;
&lt;p&gt;Without diving into NFTs and blockchain, what I'm really looking at in the
Metaverse is Facebook-branded VRChat that preys on addictive personalities. No
thanks. I don't want to contribute to a platform owned by the creepiest social
media company on Earth. In what way does the Metaverse, or other so-called
"web 3.0" software, compare to today's Web tech? Why should we want VR or even
GPU-intense games on the Web?&lt;/p&gt;
&lt;p&gt;Metaverse and anything else built on NFTs and cryptocurrencies is just &lt;em&gt;an
application&lt;/em&gt; of what Web 3 actually is. Not will be. Is.&lt;/p&gt;
&lt;p&gt;If we divide the history of the Web into eras, we get three distinct periods of
development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sharable, linkable documents. Early forums and fansites, early e-commerce,
  early rich media&lt;/li&gt;
&lt;li&gt;Syndication, blogging, early streaming, social sites and big-business
  e-commerce&lt;/li&gt;
&lt;li&gt;Web as a Software Platform; expanding to the desktop and mobile, analytics
  booms, data brokerage becomes a thing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Buckle up, stay a while and listen.&lt;/p&gt;
&lt;h1&gt;Web 1: The Beginning&lt;/h1&gt;
&lt;p&gt;Tim Berners-Lee began development on HTTP, HTML, and CSS (and thus the Web) in
1989, but the W3C wouldn't exist until 1994, and the protocol wasn't finalized
until 1996. However, plenty of early Websites (such as WikiWikiWeb, which
inspired the creation of Wikipedia) existed in this early time.&lt;/p&gt;
&lt;p&gt;In Web 1, the paradigm was the document that can link to other documents with
a click. Servers could do things, but computing resources were scarce in the
'90s, so they kept it simple like visitor counters or variable replacement. This
lasted quite a while as the dominant paradigm, but plenty of effort went into
making the server side smarter and the client side prettier. The Web gained
things like CGI servers, and support for higher level languages like Perl and
PHP through server modules. Server Side Includes, ColdFusion, and ASP were also
created in the Web 1 era.&lt;/p&gt;
&lt;p&gt;Over time, HTTP gained support for more headers, which could better inform the
server how to serve the page. This included things like smart Content-Type
handling, serving different markup for different browsers &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, and other
tricks. The cookie was invented during this time, too, so browsers could send
certain data for every request, and the server could process (and update) said
data as needed. This was used for logging into a site (a novel concept at the
time!), remembering site settings, or early e-commerce. Speaking of e-commerce,
back then you were required to purchase a security cert from a company if you
wanted to process payments online. Let's Encrypt wasn't a thing, and eBay and
PayPal wouldn't exist until 1998. SSL was much slower than unprotected Web
back then, due to the decryption step and limited hardware support for the
algorithms.&lt;/p&gt;
&lt;p&gt;In the late Web 1 days, it gained plugin support in most browsers. This allowed
support for Java and Macromedia (later Adobe) Flash, right in the browser! This
jump in abilities for the Web allowed media-heavy sites to exist, like Joe
Cartoon, Homestar Runner, Newgrounds, Yahoo Games, and Neopets.&lt;/p&gt;
&lt;p&gt;I would put the end of Web 1 around 2001-2002.&lt;/p&gt;
&lt;h1&gt;Web 2: The Explosion&lt;/h1&gt;
&lt;p&gt;The Web 2 days were marked by a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/2, HTML 4, and CSS 2&lt;/li&gt;
&lt;li&gt;rounded borders, gradients, and diagonal stripes on EVERYTHING&lt;/li&gt;
&lt;li&gt;link sharing and syndication&lt;/li&gt;
&lt;li&gt;early social media, topic-based sites&lt;/li&gt;
&lt;li&gt;blogging&lt;/li&gt;
&lt;li&gt;Javascript starts getting beefy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The biggest thing to happen in the Web 2 era is the ease of access to a server.
Web 1 had Angelfire and Lycos and friends, but Web 2 had cheap shared hosting
and project-specific hosting, like Wordpress. Becoming a web developer in this
era was easy, and due to how new it was for a lot of small businesses, it was a
great time to be a capable web developer. Groups were forming to create better
compatibility between frameworks, there was a big push in the industry &lt;em&gt;and&lt;/em&gt;
community to upgrade skills and clean up the markup. Accessibility for the blind
and other impaired people also became an initiative.&lt;/p&gt;
&lt;p&gt;In doing a lot of this work, designers began to pay some real attention and
effort to website design. Websites like &lt;a href="http://csszengarden.com"&gt;CSS Zen Garden&lt;/a&gt; were created, to
show what's possible JUST with HTML and CSS. The same rings true today, with
even more possible now thanks to CSS 3 transitions and animations.&lt;/p&gt;
&lt;p&gt;As part of this trend, a lot of websites began adopting a similar look: usually
rounded borders around their main content, with a header containing a vertical
gradient. The background would be a muted, low contrast alternating diagonal
stripe pattern. Some later Web 2 sites would try to go for a "glass" look,
similar to Windows 7's taskbar.&lt;/p&gt;
&lt;p&gt;This era also gave rise to topic-dedicated social sites. While the late Web 1
era had LiveJournal and Xanga, Web 2 gained things like Deviantart, Flickr,
Imageshack, and numerous file hosting websites, meant solely just to link to
others. This could be understood as early cloud storage. Combine this with the
prevalence of pre-built Web packages like Wordpress, phpBB, SMF, and others, and
we see a Web of interaction and sharing.&lt;/p&gt;
&lt;p&gt;A key part of this sharing was syndication. RSS and Atom are two such standards
used to facilitate this. All it is is a "feed", or list of items. When the
website publishes, the feed updates. So all you have to do is check if your feed
updated to see if there's a real update. This avoided you having to visit every
day, or F5 periodically. Blogging took off due to the advancement of this tech,
and it created thousands of communities worldwide.&lt;/p&gt;
&lt;p&gt;A big issue of this era was finding reliable links with fun, interesting, or
valuable info. Search engines existed, but they weren't as refined and weren't
as good at indexing the relevant data. What if, instead of linking to someone
every time a topic came up, you could post your bookmark &lt;em&gt;as the topic itself&lt;/em&gt;?
Community link-sharing websites came together, like Fark, Digg, and later
Reddit. (Yep, it was founded in 2005!) There were some underground ones, too.&lt;/p&gt;
&lt;p&gt;Myspace launched in 2003. It was one of the first websites that allowed you to
add a "friend". You could also rank your friends, and have custom CSS on your
profile. There was a huge attraction to Myspace, partly for this customization,
and the built in blogging feature. It was around this time that some began
suggesting to use real names online, to find people you knew. This was counter
to the prevailing knowledge of "cover your ass and use a pseudonym". As we
see today, there are very real risks and problems when you use your real name
online. That didn't stop people back then, though.&lt;/p&gt;
&lt;p&gt;Facebook was launched in 2004. It wasn't opened up to the general public until
around 2007. Soon after, it got games and began expanding into other avenues of
social activity, like Marketplace, Business and Group pages, etc.&lt;/p&gt;
&lt;p&gt;Others contended around this time, sometimes for different purposes. Friendster
was one of the first social media sites, but it never took off. A lot of dating
sites and job boards popped up on the Web around this time, too.&lt;/p&gt;
&lt;p&gt;HTML 5 and CSS 3 were released in the late Web 2 era. With them came better
parsing support due to clearer markup rules, rounded borders without images,
images as borders, composite layering inside the background of an element, and
many other Quality of Life improvements. HTML 5 and CSS 3 wouldn't gain their
crazy features like animations and Web platform integration until Web 3. At the
end of Web 2, the canvas element was being played with and some small games were
released.&lt;/p&gt;
&lt;h1&gt;Web 3: The Panopticon&lt;/h1&gt;
&lt;p&gt;The start of Web 3, I think would be somewhere around the time NodeJS and
Electron came onto the scene. WebRTC, WebGL, and EME are also key to this era.&lt;/p&gt;
&lt;p&gt;I posit that we are already in Web 3. Web 3 is Web as a Software Platform.
In this era, the Web gained support for restricting the freedom of viewers
through Encrypted Media Extensions (thanks for &lt;em&gt;selling out&lt;/em&gt;, Tim), lots of new
headers to better control inter-site behavior, and new tech that only works on
the Web, like WebAssembly, WebGL, WebUSB, WebRTC, and so on. This is distinct
from Web 2 in that it's continuous effort to turn the Web into a platform
that's as equal to a universal OS as it can be. However, this results in a lot
of over-engineering and actively prevents new browser makers by raising the
technical floor so high that only multi-billion dollar companies like Google
can negotiate licensing for EME code and devote the resources to standards
adherance.&lt;/p&gt;
&lt;p&gt;Some people and companies actively build ONLY for the Web, and containerize a
browser on as many different platforms as possible to achieve that effect. It's
kind of like using the Web as a virtual machine language like Java.&lt;/p&gt;
&lt;p&gt;One of the reasons I think Web 3 is popular, for companies at least, is the
evolution of tracking technology that began as a curiosity in the Web 2 era. If
you implement your software on the Web, you get most of the groundwork done for
free, devs are cheaper, and other companies like Google want your users data, so
they'll help you track and optimize your site for revenue, for the price of the
data and some fees, of course.&lt;/p&gt;
&lt;p&gt;Another facet of Web 3 is using it for things like text editors, IDEs, and other
productivity software. This can be done in a serverless way using Electron. Have
you noticed a pattern here though? Most of the advancement of Web 3's tech has
come from Google, a company that was born on the Web in 1998 as a search engine.
Today, it has a vested interest in gathering as much information as possible
since it sells ad space and analytics tech to other companies. Making it simple
and easy to build an application in Electron and hook it up to Google Analytics
makes Web as a Software Platform (Web 3) an easy sell for small business and is
hugely profitable for Google.&lt;/p&gt;
&lt;p&gt;The big problem I have with Web 3 is the total disregard for privacy and
security that the major writers of the Web have for those that visit, and
the intent on expanding the Web into an unmaintainable mess of standards.
So little of Web 3 technology is meant to enrich the Web for &lt;em&gt;everyone&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It's mostly a monetization platform with flashy things that give you more
access to the client's system so you can manipulate or control what's possible
on your site or app. The advantages of deploying on the Web are countered by
massive RAM use compared to a native program, fitting a square peg into a
round hole, and the continuous invasion of privacy that gets hand-waved with
as-of-yet-unchallenged Privacy Policies. Perhaps governments are right to want
to regulate &lt;em&gt;some&lt;/em&gt; aspects of Web development, if corporate participants can't
behave themselves.&lt;/p&gt;
&lt;p&gt;(Psst, America and the EU are both looking at ways to hold tech companies
accountable for how they conduct business online, especially in regards to user
data and viewing algorithms, given that the misuse of social media has led to
disruption of elections.)&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;There is way too much history, too many websites, and too many cool side
things that evolved in or next to the Web over the years to cover it all in an
article about eras of the whole thing. Things like microprotocols via markup,
decentralized social media like StatusNet and ActivityPub, Tor, freenet, ssb,
the list goes on. So if I missed anything, know that it's not because I don't
know about it. I probably do. :P&lt;/p&gt;
&lt;p&gt;The main reason I wrote is to counter the idea that Web 3.0 is on the horizon,
like some tech companies or uninformed communities want us to believe.&lt;/p&gt;
&lt;p&gt;The Web has already reached its third major era. If you use VSCode, Atom,
Etcher; if you use codepen, ideone, or Google Docs... you're using Web 3 stuff.
We reached Web 3 when we built traditional software with Web tech.&lt;/p&gt;
&lt;p&gt;Web 4 will probably be when it goes truly decentralized, or a bare metal OS
is implemented in Web tech. (ChromeOS doesn't count; it's Gentoo Linux with
an Android emulator) Who knows; right now it's looking like the Web has been
taken over by Google, both in terms of market share and in terms of "who guides
the standards". However the Web moves ahead, it needs to do so while keeping
businesses from snuffing out the rest of the community, or using their greater
resources to fill positions and exert undue influence over the technical
community.&lt;/p&gt;
&lt;p&gt;The modern Web giants do not play nicely with others, and the greatly increased
complexity of Web tech has forced a duopoly in mainstream browsers. To my
knowledge, Google &lt;em&gt;still&lt;/em&gt; pays Mozilla to be the top search engine, so they're
paid competition... There are only two others that I know of in development
(Pale Moon/Goanna and Serenity) that are anywhere close to Firefox and Chrome in
features. Netsurf and Dillo exist, but from what I can tell are stagnating...
probably due to lack of people to contribute and the sheer number of standards
you need to implement to call yourself a browser.&lt;/p&gt;
&lt;p&gt;I think a fork of HTTP is inevitable, due to its complexity. It either needs
to branch off and serve app developers, or resist corporate influence and
selectively choose the standards they support. Bonus points if they explain why
they won't implement certain tech. It sends a clear message of differentiation, 
reminding me of the fun server &lt;a href="https://tildegit.org/solderpunk/shizaru"&gt;shizaru&lt;/a&gt;, which allows you to set 
specific limits on what you're serving..&lt;/p&gt;
&lt;p&gt;Where do you think the lines between Web eras are? I'd love to read peoples'
ideas on this.&lt;/p&gt;
&lt;p&gt;Thanks for reading,&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;This was really a thing. Netscape and IE both had some big
 incompatibilities in the early days. Even their Javascript implementations
 were largely incompatible!&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Software"/><category term="HTTP"/></entry><entry><title>Free Software *is* Politics</title><link href="https://zlg.space/blog/free-software-is-politics.html" rel="alternate"/><published>2022-04-21T00:00:00-07:00</published><updated>2022-12-12T00:00:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2022-04-21:/blog/free-software-is-politics.html</id><summary type="html">&lt;p&gt;It seems that &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/33329"&gt;the systemd debate has made its way to Alpine Linux&lt;/a&gt;, and
naturally that gets people out of the woodwork to &lt;a href="https://christine.website/blog/politics-cudgel-experimentation-2022-04-21"&gt;bang their drum about it
again&lt;/a&gt;. The irony's not lost, either. It's really tiring to see people
complain about politics, in a software movement that's entirely about the
politics of software to begin with. Have you guys forgotten why we're here? Are
you more open source instead of free software? That's still a political
statement; one of practicality and reduced costs.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;It seems that &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/33329"&gt;the systemd debate has made its way to Alpine Linux&lt;/a&gt;, and
naturally that gets people out of the woodwork to &lt;a href="https://christine.website/blog/politics-cudgel-experimentation-2022-04-21"&gt;bang their drum about it
again&lt;/a&gt;. The irony's not lost, either. It's really tiring to see people
complain about politics, in a software movement that's entirely about the
politics of software to begin with. Have you guys forgotten why we're here? Are
you more open source instead of free software? That's still a political
statement; one of practicality and reduced costs.&lt;/p&gt;


&lt;p&gt;For those unfamiliar, Alpine Linux is a Linux distribution (NOT GNU/Linux)
powered by busybox, musl libc, and OpenRC. By contrast, systemd is a project
aiming to provide a "system layer" between userland and the kernel. It
explicitly depends on a recent build system (meson) and generally only supports
glibc and the Linux kernel. It explicitly does not support any alternative
libc. In short, Alpine and systemd go together like oil and water, on purely
a technical basis. The social half even moreso, since this incompatibility
resulted in users having access to a simpler system that isn't built on systemd.
Choice is great, right? Some disagree, but they're free to make their own
projects.&lt;/p&gt;
&lt;p&gt;When dealing with the systemd debate, many try to reduce it to the early years
of the debate, where people used the false dichotomy of technical and social.
Or they derail and assume it's a personal vendetta against Lennart Poettering,
without accounting for Lennart's behavior when he was advocating for systemd,
and the smug ways that his project has treated contributions, criticisms, and
distros like Gentoo. We do personal responsibility, first impressions, and all
that civil shit, right? Can we not apply this to our fellow developers? Are we
not responsible, to some degree, for how others perceive us and our projects? If
so, then I think it's fair to criticize a developer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lists.freedesktop.org/archives/systemd-devel/2014-May/019657.html"&gt;Lennart said "Gentoo, this is your wakeup call,"&lt;/a&gt; concerning the ability to
run udev without systemd, when eudev was created. &lt;a href="https://mail.gnome.org/archives/desktop-devel-list/2011-May/msg00427.html"&gt;He actively asked GNOME to
depend on systemd.&lt;/a&gt; Granted, GNOME was probably going to use it anyway due to
Red Hat employing both Poettering and many GNOME developers... A number of Arch
developers (particularly its sysvinit maintainer) were early contributors to
systemd. It's safe to say, influencing other projects is the bread and butter of
the systemd project, and I challenge anyone to argue otherwise.&lt;/p&gt;
&lt;p&gt;If you're going to participate in the debate, at least understand the history of
the project and the actions of the principal authors -- cultural origin matters
here because their values are baked into the project. The discussions from
the Arch and Debian communities are also worthwhile, to show examples of how
NOT to deal with the issue. Arch promised sysvinit would remain as an option,
then pulled the rug out from users with their switch. Debian had an &lt;em&gt;ugly&lt;/em&gt;
debate that resulted in some developers leaving the distribution altogether, and
sparked the creation of the systemd-free Devuan distribution.&lt;/p&gt;
&lt;p&gt;Arch and Debian both went systemd, while Fedora and SuSE leaned into systemd
first. As a witness to both Arch and Debian's decisions as-it-happened, the
one thing most distro devs missed was user transparency. Whatever plan you go
with, you need a pathway for the users who get left out, or you're going to
create a rift in the community or even a fork. So many users who didn't want
systemd got stuck with it. Some people who were using systemd on neutral distros
found themselves having to make a decision, where there wasn't a need to before.
Systemd support was not uniform across the ecosystem (wrt build options), and
still isn't.&lt;/p&gt;
&lt;p&gt;The decisions affected a ton of users, ironically creating &lt;em&gt;more&lt;/em&gt; forks and
attempts to maintain control of one's computing -- the dreaded "fragmentation"
boogeyman, often coming from those who don't see the value in a diverse software
ecosystem. The fatal flaw of consolidation is the assumption that every
developer in the problem space can agree on how its problems get solved. Given
human nature, that is very flatly a false assumption. Every solution in software
has different benefits and pitfalls. Some optimize for CPU speed. Some for
memory. Some for I/O. Others for networking! No single project can solve every
problem in a space. The solution to this is coexisting via multiple projects,
all of which can solve the problem(s) in the style that they choose. The
openness of software diversity is why systemd had a chance of adoption at all.&lt;/p&gt;
&lt;p&gt;The ways that various distributions handled their decisions were decidedly high
temperature, and it's clear from the beginning of the systemd project that
it was intent on changing distributions. Denying that is to side with groups
trying to manipulate the ecosystem into carrying their software on every default
install. It's competitive behavior that has no place in a collaborative
environment.&lt;/p&gt;
&lt;p&gt;Not every piece of disruptive software causes this much trouble, though. One of
Lennart's other projects, PulseAudio, hasn't caused nearly as much trouble even
though it, too, has its share of critics. I posit that the limited scope of the
project and its less aggressive appeal to the ecosystem allowed it to coexist
with ALSA and JACK in a better way than systemd does with other inits. Many
environments can treat PulseAudio as "another supported stack" with a little
maintenance, without upsetting their software's architecture.&lt;/p&gt;
&lt;p&gt;Even the Wayland project, with its own brand of smugness and the specific goal
of replacing X11, hasn't done much to create an actual, damaging rift in the
communities they are near. Programs can support both Xorg and Wayland; at least
for the features that they both share.&lt;/p&gt;
&lt;p&gt;It could also just be the nature of init systems. You generally have to make
an all-or-nothing decision. Coexisting init or service systems are a somewhat
new idea, which is why most distributions choose a single init. Apparently it's
possible, though, to mix and match between OpenRC, s6, and runit. Neat.&lt;/p&gt;
&lt;p&gt;The technical and social are inescapably intertwined, just like politics is
to free software. Two sides of the same coin. The movement itself began as
the desire to fix a printer driver and compute &lt;em&gt;their way&lt;/em&gt;. Furthermore, the
decision of which packages to include in a distribution is also political. It
affects the "computing lives", for lack of a better phrase, of the users who
trust the distribution's choices on software, or are otherwise aligned with
their software philosophy. Anything that has far-reaching consequences on how
people interact or conduct themselves could be interpreted as political.&lt;/p&gt;
&lt;p&gt;So, what's really being called for when we're asked to "stahp being political"?
To ignore the social history of a project? To censor jokes we don't find
funny? To ignore prior debates, the outcomes of said debates, or the project
management of upstream? Software isn't developed in a vacuum, and software
with a big picture agenda (anything involving the desire to standardize is
automatically political) is not doing itself any favors by accusing others
of being problematic, when &lt;em&gt;the politics is the point&lt;/em&gt;. It comes off as
intellectually dishonest or in bad faith.&lt;/p&gt;
&lt;p&gt;Why &lt;em&gt;shouldn't&lt;/em&gt; we consider the whole when we make software decisions? If given
the choice between two technically identical upstreams, would you rather deal
with the upstream who's helpful and receptive to contributions and doesn't
mind if people don't use their software, or one that sees itself above you,
decides the structure of your system without helpful or constructive feedback
for contributions, wants every system you touch to run their software, and has a
nasty habit of displacing other software? You sure that last part is really an
oopsie? Am I "not allowed" to notice that part?&lt;/p&gt;
&lt;p&gt;I know what I'd choose, and it doesn't have to be highly personal. It's a matter
of one's own software standards. As a programmer, I find it shameful to push
one's project in a way that creates a lot of discord in the community. I don't
try to get people to use VGStash over Backloggery or their other favorite game
manager, but I might bring it up in a conversation if someone doesn't sound sure
of how they want to fix that problem, and it's relevant to the conversation.
Even then, I'd rather know that I have users because they like the software, and
not because I screamed about it from the digital rooftops or pressured people
into using it. That's a false merit, if anything.&lt;/p&gt;
&lt;p&gt;Coexisting as a software project is not particularly hard. I could not, in good
conscience, act in the ways that Lennart has regarding systemd, even if it was
my own project. While some of the responses he's gotten have been over the top
(death threats? Crazy), I think it's entirely fair to apply my personal standard
to my software choices, and the people who write them.&lt;/p&gt;
&lt;p&gt;I think there are many other people in free software who use similar criteria to
determine which software they use. This is especially important for software
that you think you might contribute to! If you don't like the ideas of the
author, or their tech choices, or their philosophy to software, those are valid
reasons to avoid their software! It's also valid to tell others that's your
reason. They don't have to agree with you.&lt;/p&gt;
&lt;p&gt;But, I have to question the motives and values of a person who tells me to stop
paying attention to the politics that happen from a project with a decidedly
political aim. The technical and social parts of free software cannot be
reliably separated, any more than a human being's identity can be separated
between heart and mind. Separating the art from the artist only shows half the
picture.&lt;/p&gt;
&lt;p&gt;Focus on the whole, and make the right decision for your computing. No outside
entity knows your needs better than you do.&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;
&lt;p&gt;(Who can read the &lt;a href="https://www.gnu.org/gnu/manifesto.html"&gt;GNU Manifesto&lt;/a&gt; and not gather that it's political?)&lt;/p&gt;</content><category term="Software"/><category term="systemd"/><category term="Libre Software"/><category term="Linux"/></entry><entry><title>GNOME as a Platform</title><link href="https://zlg.space/blog/gnome-as-a-platform.html" rel="alternate"/><published>2021-10-28T00:00:00-07:00</published><updated>2022-12-12T00:00:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2021-10-28:/blog/gnome-as-a-platform.html</id><summary type="html">&lt;p&gt;I came home today and strolled my usual Web haunts before diving into the
Underground, and stumbled across a piece by GNOME developer jwestman, titled
&lt;a href="https://www.jwestman.net/2021/10/26/platforms-compatibility-the-future-of-the-free-desktop.html"&gt;Platforms, Compatibility, and the Future of the Free Desktop&lt;/a&gt;. In it,
he advocates for GNOME (and by extension XDG) to become &lt;em&gt;the&lt;/em&gt; platform that
"everyone can work on together". Isn't it funny that the kind of people that
suggest this are always talking about the platforms, software, or APIs that
&lt;em&gt;they&lt;/em&gt; have control over? Does this person not understand why people choose
other software, or choose to create something different? Do they not understand
the risks present when the vast majority of your userbase is on one or two
platforms and a 0-day is found?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I came home today and strolled my usual Web haunts before diving into the
Underground, and stumbled across a piece by GNOME developer jwestman, titled
&lt;a href="https://www.jwestman.net/2021/10/26/platforms-compatibility-the-future-of-the-free-desktop.html"&gt;Platforms, Compatibility, and the Future of the Free Desktop&lt;/a&gt;. In it,
he advocates for GNOME (and by extension XDG) to become &lt;em&gt;the&lt;/em&gt; platform that
"everyone can work on together". Isn't it funny that the kind of people that
suggest this are always talking about the platforms, software, or APIs that
&lt;em&gt;they&lt;/em&gt; have control over? Does this person not understand why people choose
other software, or choose to create something different? Do they not understand
the risks present when the vast majority of your userbase is on one or two
platforms and a 0-day is found?&lt;/p&gt;


&lt;p&gt;Something jwestman doesn't comprehend about the libre software world, I think,
is that its diversity is both a help and a hindrance. To get the best software
from the community, it needs to be able to grow, change, and adapt at the
individual level. Those adaptations will create the behavior of the ecosystem.
This is observable in wildlife, as well.&lt;/p&gt;
&lt;p&gt;Congregating the majority of an ecosystem so that they all use the same platform
is not helpful to anyone except the builder of the platform and those that
depend on them. It's &lt;em&gt;commercial&lt;/em&gt; behavior, not &lt;em&gt;social&lt;/em&gt;. These projects can
exist just fine on their own without trying to get everyone to use them.&lt;/p&gt;
&lt;p&gt;The overarching goal of organizations like GNOME are to have control over the
future of the software ecosystem. If you provide the platform, you control the
platform, you control the users. If you define the standards, you control the
platform.&lt;/p&gt;
&lt;h1&gt;Where's the incentive?&lt;/h1&gt;
&lt;p&gt;What do I gain from XDG and GNOME as a software developer? It's yet another
piece of software or interface I don't control, forcing me to update &lt;em&gt;my&lt;/em&gt;
software if I want to remain functional &lt;em&gt;ON&lt;/em&gt; your platform. It's based on
bureaucratic consensus, where decisions are gatekept by the top two funded and
top two largest implementations (GNOME and KDE). If I disagree with a decision
or propose an addition to the standards, or the interfaces, what hope does my
voice have of being heard and given honest consideration? That's the problem I
have with these organizations that are companies pretending to be communities,
so they can gain resources from the community.&lt;/p&gt;
&lt;p&gt;GNOME has not demonstrated themselves to be a good player when it comes to
collaboration. A lot of concerns have been cast aside, and their chief funding
company, Red Hat, employs these developers.&lt;/p&gt;
&lt;p&gt;Do tell me why I would want to work with such an organization. I challenge GNOME
to show the choices they allow within their platform, especially in light of the
recent &lt;em&gt;dwindling&lt;/em&gt; in options across GTK, GNOME, and GNOME core apps like the
file chooser and Nautilus. Interestingly, jwestman does a rhetorical trick where
they characterize the choices GNOME offers as "real" while other choices are
less "real". If someone switches away from GNOME, there is still a cost!&lt;/p&gt;
&lt;p&gt;GNOME is and has been obsessed with image, UX, branding, and community outreach
the past 5-8 years. To increase broader appeal, you dumb things down. Novice
users overwhelmed by options? Remove some, or hide them in dconf/gsettings!
Marketing alone isn't going to make a good platform, and neither is suggesting
people use your platform because of some fake appeal to collaboration that
doesn't hold to scrutiny if you look at your bug tracker.&lt;/p&gt;
&lt;p&gt;The direct result of coalescing on any standard is to give power to those who
wrote the standard. I do not trust the groups in charge of FreeDesktop or GNOME,
so I have no reason to learn how to write a GNOME app.&lt;/p&gt;
&lt;h1&gt;Some Thoughts on the GNOME Experience&lt;/h1&gt;
&lt;p&gt;For the record, &lt;del&gt;I'm a daily user of GNOME right now&lt;/del&gt; (nope, lol &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;),
since my laptop shipped with it as the default environment and I chose to try my
best to set it up, so I could zero in on what I dislike about it.&lt;/p&gt;
&lt;p&gt;It's a struggle to use this environment. It's a struggle to navigate the
bullshit XDG docs for defining a desktop file, so I could make a launcher for
PICO-8. The one GUI program I found to manipulate the menu and launchers didn't
have a clear interface as to which fields meant what, and the launchers it &lt;em&gt;did&lt;/em&gt;
produce didn't work. I ended up returning to the spec, and fucking around until
something finally worked. Then I needed a systemd unit to get some semblance of
"run this bash script once on boot" so I could set a sysfs value while waiting
for an EC firmware fix. GNOME also can't switch audio output when I plug in
headphones, and there isn't a GUI to fetch programs that have tray icons, like
Nextcloud and Steam. I have to use the Task Manager clone that GNOME has and
make sure it's not in the process list. (&lt;code&gt;ps aux | grep&lt;/code&gt; is loads better btw) I
often leave Steam, Nextcloud, and Mumble all in their own workspaces, to avoid
losing the windows. How on Earth is that better than a system tray!? The worst
part about this is a naive GNOME user would assume these programs are broken,
when they are not: GNOME simply doesn't implement tray icons! Load them on any
&lt;em&gt;other&lt;/em&gt; DE, and I can access the tray icons with no problem.&lt;/p&gt;
&lt;p&gt;Add to that the uselessness of the icon spec. For defining something visual, you
might want to provide a complete set of blank or example icons. Nobody wants to
navigate through the ridiculous amount of XDG-defined icon names and try to
figure out the correct one to use. Can't we use sane names, and document them
better? Half the problem are the atrocious docs. They're not written for app
developers or even independent, self-taught folks. They're written &lt;em&gt;for other
standards writers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Honestly it just feels like GNOME and XDG, if we were to consider them "a
platform", are designed to be difficult to integrate with, and you're stuck with
whatever Trolltech/KDE and Red Hat/GNOME decide on for their systems because
there's no evidence that any outside opinion would be given consideration or be
able to get any ideas merged into the standard(s).&lt;/p&gt;
&lt;p&gt;Every step of the way of my using this "platform" is a disaster. It's like it
actively doesn't want me to use it, or enjoy myself at the computer.&lt;/p&gt;
&lt;p&gt;My first Linux experience was on Ubuntu, back in 2005. It used GNOME 2 and had
tons of options and supported a great amount of shit. I got bored and frustrated
trying to customize it, so I moved onto Fluxbox and Openbox, then got into
tiling WMs: dwm, awesomewm, ratpoison, finally settling on i3-gaps.&lt;/p&gt;
&lt;p&gt;So, GNOME used to be good, and I come from an angle of control and
customizability. GNOME 3 is not good, and as a libre software developer I do not
see GNOME as a stable platform to build software on. Between version 2 and
3 there was a huge upheaval, both technical and social. GTK3 to GTK4 is already
pissing off developers and some users. What do you really have to offer other
than an API that doubles as a treadmill?&lt;/p&gt;
&lt;h1&gt;Choice is Empowering&lt;/h1&gt;
&lt;p&gt;The diversity of the software ecosystem is precisely why initiatives like XDG
could even form. Were this not possible, the platform we'd be using would in
fact be called GNU, or we'd be stuck on XFree86 or some other big project
nobody wanted to fork from at first. It's odd to me that those peddling new
technologies -- pipewire, wayland, GNOME3/4, systemd, they all lament that
there are choices in the environment and seek to actively replace other choices
instead of trying to just be a good choice. This competitive approach does not
convey an air of collaboration at all.&lt;/p&gt;
&lt;p&gt;Why should people all use one platform? "So they can gain the benefits of
standardization." Yeah I get the boilerplate answer, but think about long term
risks of using someone else's platform to build &lt;em&gt;your&lt;/em&gt; program. If FreeDesktop
changes something, now you have to change with them. "Bitrot happens," one might
riposte. Bitrot is an artificial phenomenon caused by other people intentionally
changing things so that other software does not work. It's not a magic force of
nature.&lt;/p&gt;
&lt;h1&gt;A Fractal of Projects&lt;/h1&gt;
&lt;p&gt;I think the last part of jwestman's post was the most accurate. I would take it
a step further: &lt;em&gt;computing itself&lt;/em&gt; is fragmented. We use computers for different
reasons; already, we cannot reasonably expect every interface or API to be
suitable for everyone. Standardization helps for interoperability, yes, but to
make the most of that, you need a stable spec from a level-headed, experienced
group of API writers and implementers, developers who are aware of computer
users who don't use MacBook Airs or desktops with kilowatt power supplies, and
people who are good at simplifying.&lt;/p&gt;
&lt;p&gt;The best standards are the ones easiest to understand and easiest to implement.
But another truth is, some have seen the downsides of standardization and
fully understand what you're giving up when you "just use XDG" or "just use
this framework", etc. You're inviting an entirely new set of bugs into your
code, and problems to your project. And they don't come up at first. At first,
integration's great! You &lt;em&gt;just&lt;/em&gt; read the spec and tested it a bunch. It's when
change happens upstream, long after you've committed resources to this platform,
that it bites you in the ass. And by that point, you're dealing with the Sunken
Cost fallacy. Congrats, your pet project is now dependent on Daddy Platform. Do
you beg and plead with upstream to address your problem, refactor to suit Daddy
Platform's preferences (i.e. making development decisions FOR you), or
fork/restart on another toolkit? If you choose the latter, now you're stuck for
a minimum of a few months, if your tool is non-trivial.&lt;/p&gt;
&lt;p&gt;If you build from scratch, there are only a few things that can change and upset
your project. First is any libraries you happen to use, then the standard
library of your language. Lastly, the kernel.&lt;/p&gt;
&lt;p&gt;That may result in a less integrated app, but I'm not concerned with my software
looking like it belongs in GNOME or KDE. We are never going to have One True
Interface that everybody likes. We won't have One True Audio Stack, or One True
Networking Stack. This pursuit in finding The (only) One seems... almost
religious.&lt;/p&gt;
&lt;p&gt;Personally, I like the vast software diversity available to me in the libre
software world. If XDG was the only game in town, it'd be really dull. Same for
Apache, or even just GNU. What we need is for platforms to try being platforms
on their own merits instead of parroting advocacy.&lt;/p&gt;
&lt;h1&gt;Choice is Inspiring&lt;/h1&gt;
&lt;p&gt;One of the most exciting things I experienced in libre software was realizing
"I'm not stuck with Paint or Paint Shop Pro or Photoshop!" I learned about
The GIMP, and Krita, MyPaint, mtpaint, libresprite, and so on. If we take the
ideology of "consolidate and collaborate" to its conclusion, there would only be
one image editor available for Linux, and it would have such a slew of features
it would be an unmaintainable mess. I feel the same way about platforms. Whether
it's elementaryOS, Tizen, enlightenment, GNOME, or KDE, each one has a different
flavor of GUI, with conflicting or oddly accenting views on how a GUI should
behave. As I mentioned before, humans use computers differently. That should
reflect in their interfaces, and yes, even their choice of software.&lt;/p&gt;
&lt;p&gt;As for The Free Desktop, it's been around for a long time, and it's practically
a meme at this point. What people are shooting for with the Linux desktop now is
mainstream appeal. That is not going to result in improved software, any more
than adding more people to the Internet will improve its discourse. What we're
more likely to see is less helpful bug reports, burned out or frustrated triage
devs, lots of stupid community positions to fill, arbitrating all this labor
coordination now needed from the influx of users... it sounds a lot like the way
a business grows...&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;So yeah, I dunno who jwestman thinks they're fooling. A platform isn't what
GNU/Linux needs. It needs APIs that can be left alone for a year or two and not
need babysitting because upstream took Adderall and is gazing at glowsticks
while they design the next iteration. If things are designed well, they
don't need to be changed as much. Platforms need to be stable, predictable,
reproducible, portable, and perhaps MOST importantly, slow moving!&lt;/p&gt;
&lt;p&gt;Ideally, we shouldn't be asking anyone to waste lines of code on a standard
that's not ready to be finalized in print. It's disrespectful to ask developers
to rely and build on something you can't make any stability or mutability
promises on. It's like building a Jenga tower on a table someone lent to you,
but they shake the table every so often, ruining your progress up to that point.
Would you want to build on that surface anymore? I wouldn't.&lt;/p&gt;
&lt;p&gt;Stay independent, fellow devs.&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I no longer run GNOME on my laptop, mostly due to the lack
of a proper tray without using an extension, and issues capturing windows in
OBS. There doesn't appear to be a way to run or build OBS so that it sees both
Wayland and X11 windows. Since most of my software was X11, I switched to XFCE
until I get the gumption to put together an awesome-wm or i3 config for my
laptop. While it still uses XDG standards, it at least doesn't limit me in how I
arrange my UI or spin up my GPU for fancy effects. It's quite adaptable and gets
out of the way. It also hasn't crashed yet.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Software"/><category term="GNOME"/><category term="XDG"/><category term="Libre Software"/></entry><entry><title>Refactoring My File Hierarchy</title><link href="https://zlg.space/blog/refactoring-my-file-hierarchy.html" rel="alternate"/><published>2020-06-20T21:06:00-07:00</published><updated>2024-07-16T02:35:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2020-06-20:/blog/refactoring-my-file-hierarchy.html</id><summary type="html">&lt;p&gt;When I returned to mkbak&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; in order to give it better options for custom
backup naming, automatic date tagging, preservation of permissions, etc., I
noticed that I was writing complex and tricky rsync filter files. I ran with
this for a while -- and still have them as I write this -- but the problem
stewed in my mind. Something bothered me about the organization of the files
under my $HOME. Eventually, I felt there was a way for me to shorten my rsync
filter files &lt;em&gt;and&lt;/em&gt; reduce the stress I felt about my files. I just needed to
figure out what the core problem was. To answer that, we need to understand what
hierarchy's purpose is, or what its use introduces to your data.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;When I returned to mkbak&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; in order to give it better options for custom
backup naming, automatic date tagging, preservation of permissions, etc., I
noticed that I was writing complex and tricky rsync filter files. I ran with
this for a while -- and still have them as I write this -- but the problem
stewed in my mind. Something bothered me about the organization of the files
under my $HOME. Eventually, I felt there was a way for me to shorten my rsync
filter files &lt;em&gt;and&lt;/em&gt; reduce the stress I felt about my files. I just needed to
figure out what the core problem was. To answer that, we need to understand what
hierarchy's purpose is, or what its use introduces to your data.&lt;/p&gt;


&lt;h1&gt;Establishing the Branch Points&lt;/h1&gt;
&lt;p&gt;Academics can give you a more elegant explanation, but I understand hierarchy
to be the way we divide and group objects of a type. Each split in the tree
should be a meaningful distinction between groups of data. This distinction then
facilitates easy browsing or finding of files. Of course, this is in theory,
and to a certain point of nesting. If you're drilling down 17 levels, maybe try
tagging! :P&lt;/p&gt;
&lt;p&gt;So, to start with my backup file lists were getting complex. I added
dot-folders, excluded cache folders and other transient files, made exceptions
for in-git config files or in-mkbak, and mixed the origins of the files I was
managing. That's when it hit me: I care about "I made this" or "someone else
made this". That was the first meaningful division in my refactor. I treat files
made by me as MUCH more important than those by others, though I still have
local git copies of a lot of software I use, and distfiles for everything else.&lt;/p&gt;
&lt;p&gt;Suddenly I noticed there was a lot to sort through. I had books and RFCs and
specs mixed in with my articles, notes, and Ledger journals. I had icons
mixed in with Pixel Art instead of being at the top level of Artwork. Some
directories, like my music, weren't clear "Am I allowed to have this file?"...
so there was another good distinction.&lt;/p&gt;
&lt;p&gt;Next, I remembered that some music albums, games, or even software was bought by
me, and due to the Copyright Act of 1976, one may keep a single archival backup
of media, but only for personal use to protect your purchase. That meant I
needed a place to put my dumped cartridges, Humble Bundle games, SoundCloud
albums, retail albums, etc.&lt;/p&gt;
&lt;h2&gt;A Brief Breakdown&lt;/h2&gt;
&lt;p&gt;By this point I had four "buckets":&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mine&lt;/li&gt;
&lt;li&gt;Others&lt;/li&gt;
&lt;li&gt;Disallowed&lt;/li&gt;
&lt;li&gt;Purchased&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I couldn't think of another distinction that was big enough to belong at the
top level, so I went with the four to start with.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Mine&lt;/strong&gt; tree covers files created or maintained directly by me. Stuff like
family albums, projects, artwork, prose, etc.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Others&lt;/strong&gt; tree is for files made by others that are legal to have a
personal copy of and/or are free to distribute in unmodified form. This includes
code repositories, software binaries of freeware, etc.&lt;/p&gt;
&lt;p&gt;Naturally, &lt;strong&gt;Disallowed&lt;/strong&gt; just shows me what I need to delete, or purchase a
copy if I liked it. Good to have separate. It was surprisingly much smaller than
I expected.&lt;/p&gt;
&lt;p&gt;Lastly, &lt;strong&gt;Purchased&lt;/strong&gt; is an attempt to catalog and account for my purchased
digital files, to prove their legitimacy.&lt;/p&gt;
&lt;h1&gt;Improving the Hierarchy's Usability&lt;/h1&gt;
&lt;p&gt;These initial groups already gave me insight into my file collection, but I
thought about further classification or "features" I wanted in my hierarchy. I'm
still shopping for a new OS; Where would I put VMs and their scripts? What about
WINE-compatible installer binaries? I also wanted a "scratch area" that would
store files that need to persist between boots&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, but aren't yet ready to be
added to the hierarchy.&lt;/p&gt;
&lt;p&gt;This part is actually much simpler for me, because I already organized my files
by their type. Well, generally anyway. This was an opportunity to improve it. It
wasn't that bad to basically swap directories around, rename a few things,
update a few configuration files... With each directory I had sorted, I felt
like the files were reaching a meaningful location for me that I didn't need to
think too hard about.&lt;/p&gt;
&lt;h1&gt;Enter GNU Stow&lt;/h1&gt;
&lt;p&gt;That's when it hit me: "Didn't I hear about some way to map or merge
directories, or manage symlinks?" I did, actually. &lt;a href="https://www.gnu.org/software/stow/"&gt;GNU Stow&lt;/a&gt; is exactly that:
you manage a set of 'packages' that roughly match up to directory trees and then
merge them into wherever you want, to make it appear as if the files from all
the others are in one place. &lt;em&gt;Exactly what I needed.&lt;/em&gt; As a bonus, you can setup
a given directory as STOW_DIR (I used /usr/local/stow) and then symlink your
packages from there, so you aren't needlessly copying files or moving dirs
around.&lt;/p&gt;
&lt;p&gt;As a test of GNU Stow, I took music that was freely available and music I had
purchased, which were in two different directories, symlinked to them in the
STOW_DIR, merged their contents with GNU Stow, then hooked that directory up to
real software to make sure it worked. Here's what it looked like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/usr/local/stow/
  ├── music_others -&amp;gt; /home/zlg/others/music/
  └── music_purchased -&amp;gt; /home/zlg/me/purchases/music/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, I just ran a single command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;stow&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;/usr/local/stow&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;~/music&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;music_others&lt;span class="w"&gt; &lt;/span&gt;music_purchased
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that, I did an &lt;code&gt;ls ~/music&lt;/code&gt; and... son of a bitch, it worked! I
double-checked by opening ncmpcpp and updating the mpd database, which was
pointed to look at ~/music. The database looked the same as it did before.
Playing files worked as if the data was never split. That's what sold me on GNU
Stow's ability to produce the merged directories I'll need to pull off more fun
stuff with this hierarchy.&lt;/p&gt;
&lt;p&gt;The careful reader already knows there's a caveat coming: synchronization. How
does one keep them synced? The first solution that came to me is a cronjob that
runs stow with the &lt;code&gt;--restow&lt;/code&gt; (-R) flag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;*/15 * * * * stow -d /usr/local/stow -t /home/zlg/music -R music_others music_purchased
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You would repeat this for each stow target you want to work with. Doing it every
fifteen minutes can be a bit too often for your use case. I used a five minute
interval during testing and it didn't seem to tax my system.&lt;/p&gt;
&lt;h2&gt;Tidying Up&lt;/h2&gt;
&lt;p&gt;With these changes and automation in place, I needed to go correct a bunch of
my existing symlinks to suit the new hierarchy. It was mostly manual work, but
with a few &lt;code&gt;find&lt;/code&gt; pipelines it was trivial to find the broken links. if I were
to repeat this, I would instead have a stow package dir containing symlinks
to other files, but with the filenames that I need in $HOME for everything to
hook up nicely. I'll need to test that case a little more, because the links
would need to be relative to the target directory instead of the stow package
directory. If I pull this off, I can name it 'integration' or 'homedir' or
something, and my dotfile management will be a solved problem.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I'd be remiss if I didn't share the structure that I ended up with! I did
the vast majority of brainstorming in a neat piece of software called
&lt;a href="http://strlen.com/treesheets"&gt;TreeSheets&lt;/a&gt;. It was the first time I'd used this software, but I enjoyed it
quite a bit and will definitely use it for my next big brainstorming session.
Hierarchical spreadsheets are a wonderful idea!&lt;/p&gt;
&lt;p&gt;&lt;img alt="an exported PNG image of my Personal File Hierarchy" src="https://zlg.space/blog/images/pfh_ts.png"&gt;&lt;br&gt;
&lt;a href="https://files.zlg.space/s/eszExeFfJQaeBZH"&gt;Click to download the original TreeSheets file (.cts)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm quite pleased to have mostly solved my organizational stress problem. It's
relieving to know things are filed away in a sane and predictable manner. I'm
also happy to have another tool at my disposal that will save me time.&lt;/p&gt;
&lt;p&gt;Thanks for reading,&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;(mkbak is) A bash script that's a thin wrapper around rsync. It takes a
 single rsync filter list (to allow both including and excluding) and backs
 files up to a given location, preserving their permissions and mtime, etc.
 Maybe I will release it some time.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Due to my living situation, I no longer run the desktop all day, to
 save on electricity costs. Thus, I needed some spare "scratch" space.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Software"/><category term="Organization"/><category term="GNU Stow"/><category term="TreeSheets"/></entry><entry><title>Zettelwhat?</title><link href="https://zlg.space/blog/zettelwhat.html" rel="alternate"/><published>2020-06-06T01:03:00-07:00</published><updated>2022-06-21T21:52:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2020-06-06:/blog/zettelwhat.html</id><summary type="html">&lt;p&gt;I checked out the &lt;a href="https://zettelkasten.de/"&gt;Zettelkasten method&lt;/a&gt;, which appears to be German for
something like a box of (index) cards.&lt;/p&gt;
&lt;p&gt;The website for the method appears to be a marketing site, almost. It's not
simply and plainly spelled out for you what the method really is, and it lacks
clear, real-world steps and examples to get the most out of the method. I dug a
little and finally found the gist of it, being:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a note on a card for a single topic&lt;/li&gt;
&lt;li&gt;Give it a permanent ID&lt;/li&gt;
&lt;li&gt;Link to this note from other notes, via this ID&lt;/li&gt;
&lt;li&gt;Maintain links via a master link list&lt;/li&gt;
&lt;li&gt;Use the link lists to form associations between knowledge&lt;/li&gt;
&lt;li&gt;(Multiple link lists may be used to map your knowledge in different ways)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The grand goal is to have a well of knowledge that you can, eventually, begin to
interact with and explore the limits of your own &lt;em&gt;documented&lt;/em&gt; knowledge, which I
think is an interesting distinction to make. One of the reasons we write notes
is to externalize information in a form we can recall later, to offset the
cognitive load of short-term memory. Then we only need to remember to come back
to our note(s) to be reminded of what we already know.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I checked out the &lt;a href="https://zettelkasten.de/"&gt;Zettelkasten method&lt;/a&gt;, which appears to be German for
something like a box of (index) cards.&lt;/p&gt;
&lt;p&gt;The website for the method appears to be a marketing site, almost. It's not
simply and plainly spelled out for you what the method really is, and it lacks
clear, real-world steps and examples to get the most out of the method. I dug a
little and finally found the gist of it, being:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a note on a card for a single topic&lt;/li&gt;
&lt;li&gt;Give it a permanent ID&lt;/li&gt;
&lt;li&gt;Link to this note from other notes, via this ID&lt;/li&gt;
&lt;li&gt;Maintain links via a master link list&lt;/li&gt;
&lt;li&gt;Use the link lists to form associations between knowledge&lt;/li&gt;
&lt;li&gt;(Multiple link lists may be used to map your knowledge in different ways)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The grand goal is to have a well of knowledge that you can, eventually, begin to
interact with and explore the limits of your own &lt;em&gt;documented&lt;/em&gt; knowledge, which I
think is an interesting distinction to make. One of the reasons we write notes
is to externalize information in a form we can recall later, to offset the
cognitive load of short-term memory. Then we only need to remember to come back
to our note(s) to be reminded of what we already know.&lt;/p&gt;


&lt;p&gt;So as a habit and idea, it's nice. But when you think about it, this is exactly
how a wiki works, minus the "write once, link forever" aspect of Zettelkasten.
It's also how you would more or less add tags to data in a well-normalized
database. You would implement it using a lookup table, like "genre_lookup"
below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;      t_game                                          t_genre

+----+------------+                             +----+-----------+
| id | title      |                             | id | genre     |
+----+------------+                             +----+-----------+
| 3  | Beep Boop  |         genre_lookup        | 8  | Action    |
+----+------------+                             | 9  | Adventure |
  |                       +------+------+       +----+-----------+
  |                       | t_id | g_id |         |
  |                       +------+------+         |
  &amp;#39;---------------------&amp;gt; |  3   |  8   | &amp;lt;-------&amp;#39;
                          |  3   |  9   |
                          +------+------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This lookup table means 'Beep Boop' is Action/Adventure. (We should add Sci-Fi
too, but I digress. ;) If this were a Zettelkasten, it would be called "Game
Genres" and link games to their respective genres. It would just be in a less
verbose form, like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;game3 -&amp;gt; genre8, genre9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The exact field names aren't important, it's just an illustration. One could
have a convention for fields so you can fit more on one note. Something like
"capital G for game, lowercase g for genre" would be enough:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;G3 -&amp;gt; g8, g9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then if you really cared you'd look up g8 and g9 to find Action and Adventure. A
more pragmatic person would create a note that has the list of genres on it, and
update it (with permaIDs) as they go along in similar fashion. That way you only
look up one "note" to find all genres. Then our link card could be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;G3 -&amp;gt; 8, 9
(see: genre_table)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then the 'genre_table' note would have a simple numeric list of genre names.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This little mental exercise helped me conclude that Zettelkasten as a way of
approaching one's knowledge is interesting and maybe useful, but the tech is
more or less already implementable in traditional forms, like wikis, static
HTML, vim-wiki and org-mode, etc. Even Gophermaps can be "zettel". I think their
site could benefit from pragmatic, real-world examples of using this stuff and
a focus on how to apply the method to various media. There are apps for it, but
they all seem to have various warts, so it would be more wise to use extant
technology to try the method.&lt;/p&gt;
&lt;p&gt;Zettelkasten strikes me as a mindset or an idea rather than a method, because
it's not clear how long a zettel should be, if they should be edited or changed
over time, if links can be deleted or modified as you refine the knowledge base,
etc. An effective method has answers for these finer points, presented in a form
that's digestable in a single webpage instead of a series of blog posts waxing
philosophical about a method that amounts to tagging cards.&lt;/p&gt;
&lt;p&gt;Neat idea, but it talks itself up way too much. Just my two cents.&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;</content><category term="Software"/><category term="Organization"/><category term="Zettelkasten"/></entry><entry><title>Disable DNS over HTTPS in Firefox</title><link href="https://zlg.space/blog/disable-dns-over-https-in-firefox.html" rel="alternate"/><published>2020-02-26T23:39:00-08:00</published><updated>2022-12-11T00:37:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2020-02-26:/blog/disable-dns-over-https-in-firefox.html</id><summary type="html">&lt;p&gt;Mozilla recently changed Firefox's default behavior so that all United States
users are using technology called &lt;a href="https://blog.mozilla.org/blog/2020/02/25/firefox-continues-push-to-bring-dns-over-https-by-default-for-us-users/"&gt;DNS-over-HTTPS&lt;/a&gt;, which stuffs your DNS
queries into an HTTPS request, which then spits back the IP to connect to. On
its surface it's supposed to be "more secure", but &lt;a href="https://wiki.mozilla.org/Trusted_Recursive_Resolver#network.trr.resolvers"&gt;the default DoH provider is
Cloudflare&lt;/a&gt;. This should be alarming to anyone who considers centralization
a threat. The effect of this is that all Firefox DNS traffic will be routed
through Cloudflare, creating a funnel of information to a single provider.&lt;/p&gt;
&lt;p&gt;Cloudflare uses Google captchas and other analytics. &lt;a href="https://groups.google.com/forum/#!topic/mozilla.governance/81gMQeMEL0w"&gt;Mozilla has also been
gathering "anonymous browsing data" through their Studies platform.&lt;/a&gt; The
only real reason to gather this data is to sell it; very little of this data
is useful for the Studies program, and using hot/cold or A/B testing for
determining features is poor software design philosophy. As such, I recommend
disabling DNS over HTTPS, or running your own Trusted Recursive Resolver, if
you're going to stick with Firefox.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Mozilla recently changed Firefox's default behavior so that all United States
users are using technology called &lt;a href="https://blog.mozilla.org/blog/2020/02/25/firefox-continues-push-to-bring-dns-over-https-by-default-for-us-users/"&gt;DNS-over-HTTPS&lt;/a&gt;, which stuffs your DNS
queries into an HTTPS request, which then spits back the IP to connect to. On
its surface it's supposed to be "more secure", but &lt;a href="https://wiki.mozilla.org/Trusted_Recursive_Resolver#network.trr.resolvers"&gt;the default DoH provider is
Cloudflare&lt;/a&gt;. This should be alarming to anyone who considers centralization
a threat. The effect of this is that all Firefox DNS traffic will be routed
through Cloudflare, creating a funnel of information to a single provider.&lt;/p&gt;
&lt;p&gt;Cloudflare uses Google captchas and other analytics. &lt;a href="https://groups.google.com/forum/#!topic/mozilla.governance/81gMQeMEL0w"&gt;Mozilla has also been
gathering "anonymous browsing data" through their Studies platform.&lt;/a&gt; The
only real reason to gather this data is to sell it; very little of this data
is useful for the Studies program, and using hot/cold or A/B testing for
determining features is poor software design philosophy. As such, I recommend
disabling DNS over HTTPS, or running your own Trusted Recursive Resolver, if
you're going to stick with Firefox.&lt;/p&gt;


&lt;h1&gt;How to Disable DNS over HTTPS&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;about:config&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;network.trr.mode&lt;/code&gt;, and set it to 5. If it doesn't exist, create
   it, so when you update Firefox the key will already be made. &lt;a href="https://wiki.mozilla.org/Trusted_Recursive_Resolver#network.trr.mode"&gt;See the MDN
   wiki&lt;/a&gt; for a description of the magic numbers used here.&lt;/li&gt;
&lt;li&gt;Restart your browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Be sure to do this for &lt;em&gt;all&lt;/em&gt; Firefox installations.&lt;/p&gt;
&lt;p&gt;Who knows how long they'll allow it. At present I cannot recommend any HTTP
browsers. The whole protocol is a mess, as are the attempts to secure it.&lt;/p&gt;
&lt;p&gt;If you've been paying attention, it's become harder and harder to run your own
website, because corporations and browser vendors (one and the same here) keep
changing the requirements to be considered "secure". This is a repeat of what's
happened to the e-mail protocol, and apparently we'll need to fuck up HTTP to
relearn that lesson.&lt;/p&gt;
&lt;p&gt;We need to have a serious conversation about trust and networking. Large,
powerful organizations are trying to steer what the public does online and we're
expected to just trust them. What have they done to deserve our trust? We read
about leak after leak of data; data that wouldn't leak if it wasn't gathered in
the first place. And their answer is to trust yet another entity, that we
&lt;em&gt;don't&lt;/em&gt; have legal agreements with, to our most personal browsing information.
That's a trap, folks.&lt;/p&gt;
&lt;p&gt;None of this makes me trust the Web. It highlights how broken TCP/IP itself is.
We need a networking stack that puts security and privacy first, not as a
half-baked, cat's-out-of-the-bag "solution" through corporate partnerships and
continuously changing the requirements for Web authorship.&lt;/p&gt;
&lt;p&gt;There are solutions out there to sandbox your browser: Firejail, a chroot,
whatever "universal packaging solution" is hip on Linux these days, or just a
regular ol' VM.&lt;/p&gt;
&lt;p&gt;If you have to use all of these things dressed up to the nines to browse the
Web, then it's time to realize that HTTP(S) Is Harmful.&lt;/p&gt;
&lt;p&gt;-z&lt;/p&gt;</content><category term="Software"/><category term="Firefox"/><category term="DoH"/><category term="DNS"/></entry><entry><title>Easy diffing with Vim</title><link href="https://zlg.space/blog/easy-diffing-with-vim.html" rel="alternate"/><published>2018-10-13T00:00:00-07:00</published><updated>2018-12-06T00:00:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2018-10-13:/blog/easy-diffing-with-vim.html</id><summary type="html">&lt;p&gt;Vim has good support for showing the differences between two (or three) files
with either the &lt;code&gt;vimdiff&lt;/code&gt; command or setting up a diff session manually.
This often requires opening the files in their own window panes, then using
&lt;code&gt;:diffthis&lt;/code&gt; in all the relevant files. If you're in the middle of an editing
session, stopping to set up this diff session can cause you to lose focus. I
wrote a function in my &lt;code&gt;vimrc&lt;/code&gt; that automates this process, so the user can 
focus on making decisions instead of building their UI or some other 
flow-breaking process.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Vim has good support for showing the differences between two (or three) files
with either the &lt;code&gt;vimdiff&lt;/code&gt; command or setting up a diff session manually.
This often requires opening the files in their own window panes, then using
&lt;code&gt;:diffthis&lt;/code&gt; in all the relevant files. If you're in the middle of an editing
session, stopping to set up this diff session can cause you to lose focus. I
wrote a function in my &lt;code&gt;vimrc&lt;/code&gt; that automates this process, so the user can 
focus on making decisions instead of building their UI or some other 
flow-breaking process.&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;quot; Function: BufDiff&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; Author: zlg &amp;lt;zlg+viml@zlg.space&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; Date: 2018-10-12&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; License: GNU GPL, version 3 &amp;lt;https://gnu.org/licenses/gpl-3.0.html&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; Description: Open a new tab page with two or three buffers and enter diff mode.&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; Long Description:&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; BufDiff accepts two or three buffer arguments and opens a new tab page to&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; work with them in diff mode. This ensures that your existing window and&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; buffer layout is preserved while providing an easy way to enter a diff&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; session. The arguments can be any argument that can also be passed to&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot; the &amp;quot;:buffer&amp;quot; Ex-command, including partial filenames (if quoted).&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; BufDiff&lt;span class="p"&gt;(&lt;/span&gt;buf1&lt;span class="p"&gt;,&lt;/span&gt; buf2&lt;span class="p"&gt;,&lt;/span&gt; ...&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; fname &lt;span class="p"&gt;=&lt;/span&gt; substitute&lt;span class="p"&gt;(&lt;/span&gt;expand&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;sfile&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;^function &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;:&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        echohl ErrorMsg
        &lt;span class="k"&gt;echomsg&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:fname . &lt;span class="s2"&gt;&amp;quot;: This function accepts a maximum of three arguments.&amp;quot;&lt;/span&gt;
        echohl None
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;endif&lt;/span&gt;

&lt;span class="c"&gt;    &amp;quot; Check for a third buffer, which will default to zero if not present&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;:buf3 &lt;span class="p"&gt;=&lt;/span&gt; get&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;bufexists&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:buf1&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;bufexists&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:buf2&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="p"&gt;!&lt;/span&gt;bufexists&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:buf3&lt;span class="p"&gt;))&lt;/span&gt;
        echohl ErrorMsg
        &lt;span class="k"&gt;echomsg&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:fname . &lt;span class="s2"&gt;&amp;quot;: One or more buffer number(s) not found!&amp;quot;&lt;/span&gt;
        echohl None
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;tabnew&lt;/span&gt;
        exe &lt;span class="s2"&gt;&amp;quot;:buffer &amp;quot;&lt;/span&gt; . &lt;span class="k"&gt;a&lt;/span&gt;:buf1
        &lt;span class="k"&gt;diffthis&lt;/span&gt;
        &lt;span class="k"&gt;vsplit&lt;/span&gt;
        exe &lt;span class="s2"&gt;&amp;quot;:buffer &amp;quot;&lt;/span&gt; . &lt;span class="k"&gt;a&lt;/span&gt;:buf2
        &lt;span class="k"&gt;diffthis&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;:buf3
            &lt;span class="k"&gt;vsplit&lt;/span&gt;
            exe &lt;span class="s2"&gt;&amp;quot;:buffer &amp;quot;&lt;/span&gt; . &lt;span class="k"&gt;a&lt;/span&gt;:buf3
            &lt;span class="k"&gt;diffthis&lt;/span&gt;
        &lt;span class="k"&gt;endif&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;BufDiff()&lt;/code&gt; allows me to reference two or three open buffers and put them into
a separate diff session via a tab page. When I'm done working with the diff
session, I can &lt;code&gt;:tabc&lt;/code&gt; to close the tabpage and my original session (from the
prior tabpage) is still intact, ready for me to continue work.&lt;/p&gt;
&lt;p&gt;Using it is simple. Let's say you invoke vim with &lt;code&gt;vim foo.txt bar.txt&lt;/code&gt;.
You'll end up in Vim with the contents of &lt;code&gt;foo.txt&lt;/code&gt; (or an empty buffer ready
for writing to said file), with &lt;code&gt;bar.txt&lt;/code&gt; in a second buffer. If I do &lt;code&gt;:call
BufDiff(1,2)&lt;/code&gt;, the new tabpage will come up and compare the two files. I could
also use &lt;code&gt;:call BufDiff("foo", "bar")&lt;/code&gt;, since the arguments get sent to the
&lt;code&gt;:buffer&lt;/code&gt; Ex-command.&lt;/p&gt;
&lt;p&gt;The primary limitation of &lt;code&gt;BufDiff&lt;/code&gt; is you need the files you want to compare
to be present in the buffer list already. Many people begin working on their
projects with a one-liner that opens all the relevant source files, so it's a
limitation that I think is bearable.&lt;/p&gt;
&lt;p&gt;If you use this function, let me know how it worked out for you! Improvements 
and suggestions are also welcome.&lt;/p&gt;
&lt;p&gt;Shoutout to tockitj from Freenode's &lt;code&gt;#vim&lt;/code&gt; channel for the inspiration.&lt;/p&gt;</content><category term="Software"/><category term="Vim"/><category term="Programming"/></entry><entry><title>Handcrafting an SVG Logo</title><link href="https://zlg.space/blog/handcrafted-svg.html" rel="alternate"/><published>2018-08-18T00:00:00-07:00</published><updated>2019-04-07T18:29:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2018-08-18:/blog/handcrafted-svg.html</id><summary type="html">&lt;p&gt;If you've spent any time viewing diagrams on Wikipedia, you'll see notices on
some images that mention that the image was (re)written by hand to reduce its
size. Curious, I wanted to build something in &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt;, then rebuild
it by hand to see the difference. The old logo wasn't really working out any 
more, so it was a great opportunity to revisit the design and learn (yet) 
another markup language.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;If you've spent any time viewing diagrams on Wikipedia, you'll see notices on
some images that mention that the image was (re)written by hand to reduce its
size. Curious, I wanted to build something in &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt;, then rebuild
it by hand to see the difference. The old logo wasn't really working out any 
more, so it was a great opportunity to revisit the design and learn (yet) 
another markup language.&lt;/p&gt;


&lt;h1&gt;Step 0: Analyze your past work&lt;/h1&gt;
&lt;p&gt;This step may not be relevant if you're building an idea from scratch. For me,
the goal was to create a better logo than my previous one:&lt;/p&gt;
&lt;p&gt;&lt;img alt="the old ZLG logo" src="https://zlg.space/blog/images/logo-dev/old-logo.png"&gt;&lt;/p&gt;
&lt;p&gt;I asked, "What is this logo doing wrong?" Answering that was easy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's using a serifed font, while the website uses sans-serif. This can be
  ignored if you're aiming for a particular style, but it clashed with the soft,
  friendly lettering on what I call the "rounded squares on blue" theme. The
  font wasn't chosen with any particular purpose, and it shows.&lt;/li&gt;
&lt;li&gt;Why is it underlined? To separate it from the icons? Not a very intuitive
  choice.&lt;/li&gt;
&lt;li&gt;The icons don't appear to add much to the image. They represent &lt;em&gt;what I do&lt;/em&gt;,
  not &lt;em&gt;who I am&lt;/em&gt;. What's stopping me from adding a second row of unnecessary
  icons? A logo &lt;em&gt;is&lt;/em&gt; an icon.&lt;ul&gt;
&lt;li&gt;On that note, why did I write Hello World in C when nobody's going to read
  that text? It's showing line numbers for lines that don't have content,
  too.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The spacing between the Z and L is wider than between L and G.&lt;/li&gt;
&lt;li&gt;The spacing between the top of the icons, the line, and the bottom of the text
  isn't the same.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We'll let the last two slide for now. Overall, the logo is put together well:
it's evenly spaced around its edges and the three icons are equidistant to each
other. However, it's just a hodge podge of activities and a pseudonym with an
ill-suited font.&lt;/p&gt;
&lt;p&gt;We can do better than that.&lt;/p&gt;
&lt;h1&gt;Step 1: Sketch it out&lt;/h1&gt;
&lt;p&gt;Some people like to skip this step, but I consider it an important part of the
process. Whatever tool you use, try to use one with the least amount of
"resistance" between you and the idea. For me, it was a pencil and graph paper.
You could use a tablet, a Boogie Board, or your standard image editor. Whatever
you use, get the idea onto something, and tack on a few alternative ideas if you
have the room.&lt;/p&gt;
&lt;p&gt;&lt;img alt="sketch of new ZLG logo" src="https://zlg.space/blog/images/logo-dev/zlg-logo-sketch.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;There were a lot of ways to draw my logo. I sketched them all out and
brainstormed on possible alterations to improve the look.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Each glance at it got me a little psyched up about what it could be, until I
gave in and started &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG"&gt;learning &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt;&lt;/a&gt;. Before that, I needed to move onto
the next step.&lt;/p&gt;
&lt;h1&gt;Step 2: Build it in a vector editor&lt;/h1&gt;
&lt;p&gt;I use &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt; for visual editing of &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; files. Despite it
pushing out larger files than what you'd normally write by hand, it's useful
to transfer the sketch to the computer and, again, just &lt;em&gt;get it out there&lt;/em&gt;.
This process is iterative, so it's easier to have an image you can visually
manipulate. At this stage, I tried some variations and threw on a few guide
lines to see how I felt about the composition.&lt;/p&gt;
&lt;p&gt;Each glyph is a maximum of 8 × 8 blocks. I used 8px × 8px blocks, but you can
(and should) use larger ones -- a power of two, if possible -- to make your
image scaling-friendly. Letters have a line width of two blocks, and there must
be one block between glyphs. Seems easy enough, right? These opinions come from
working on pixel art and toying around with the grid when I made the
rounded-squares-on-blue site layout. Some designs work better in multiples of
three. Whatever you choose, make it consistent!&lt;/p&gt;
&lt;h1&gt;Step 3: Analyze your options&lt;/h1&gt;
&lt;p&gt;If you came up with enough ideas for your logo, there were probably a few ideas
that sucked. That's okay; use this step to determine which ones suck, &lt;em&gt;and why&lt;/em&gt;.
I'll go over a few of the ideas I had:&lt;/p&gt;
&lt;h2&gt;Draft 1&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Draft 1 of the ZLG logo" src="https://zlg.space/blog/images/logo-dev/inkscape-1.png"&gt;&lt;/p&gt;
&lt;!-- naive double-right Z, frame L, double-right G --&gt;

&lt;p&gt;This was one of the first drafts. A neat property of the Z is it's a rotated
mirror of itself along its spine (see the diagonal blue line striking through
it). I like that, but the top and bottom arms look like I just sawed off the
ends without caring about how it looks. It almost looks like the Z has a drop
shadow, which isn't what I'm looking for.&lt;/p&gt;
&lt;p&gt;The L looks like someone cut a box in half diagonally. The bottom leg is too
long. Shortening it by one block will give it a more natural shape, since we
don't normally write L's with such a long leg.&lt;/p&gt;
&lt;p&gt;The G actually looks kinda slick since the edges line up and have the
"razor cut" feel. Still, there's a little &lt;em&gt;too&lt;/em&gt; much parallelism happening for
me.&lt;/p&gt;
&lt;h2&gt;Draft 2&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Draft 2 of the ZLG logo" src="https://zlg.space/blog/images/logo-dev/inkscape-2.png"&gt;&lt;/p&gt;
&lt;!-- Z has X-like guide lines, L's leg was shortened, bottom edge of G reversed
--&gt;

&lt;p&gt;This one addresses the issues I had with each of the letters: the Z's edges
create an X with the guide lines, right in the center. To me, that's a hint that
you're doing things correctly. There's a symmetry to it. The L's leg was
shortened, and the G's bottom line edge just flipped. So far so good... except
the line width of the G's curve. See how it's just shy of two blocks wide?
That's a bit of an issue.&lt;/p&gt;
&lt;h2&gt;Draft 3&lt;/h2&gt;
&lt;p&gt;It's an easy fix: just move the handles of the cubic Bezier curve out a little.
Doing this breaks the grid a little bit in terms of curve handle placement, but
it achieves the end goal of matching line width:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Draft 3 of the ZLG logo" src="https://zlg.space/blog/images/logo-dev/inkscape-3.png"&gt;&lt;/p&gt;
&lt;!-- width of G's curve is fixed --&gt;

&lt;p&gt;See? Now the G's curve's width is roughly 2 blocks wide. It's actually slightly
wider, but tweaking this too much is a waste of time for now. We have things
essentially where they need to be. There are two blocks of spacing around the
logo, one block between each letter, and each letter matches the requirements
for style.&lt;/p&gt;
&lt;h1&gt;Step 4: Write the &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt;&lt;/h1&gt;
&lt;p&gt;If you're lazy or don't care about file sizes, you can edit the Document
Properties in Inkscape, fill it in, save it, and forget about it, but I've
read about ways for SVGs to be smaller and more powerful, so it was a great
opportunity to learn &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; syntax. That way, all I need is a browser and a text
editor to build a vector image. Before we crack open our favorite text editor,
let's get a look at where our vertices will be:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image of ZLG logo with
vertices" src="https://zlg.space/blog/images/logo-dev/inkscape-vertices.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Hint: You can do this in Inkscape by clicking on the Node tool (F2 by default)
and hitting Ctrl+A to select all paths)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Great, we have our vertices, along a configured grid. This is all we need to
copy it in text form!&lt;/p&gt;
&lt;p&gt;Mozilla has good &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG"&gt;documentation on &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; structure&lt;/a&gt;, which was
instrumental to my learning. Here's the markup and final result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;&amp;lt;!-- ZLG Logo, Copyright © 2018 zlg. All rights reserved. Source provided for&lt;/span&gt;
&lt;span class="cm"&gt;educational use. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2000/svg&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;xmlns:xlink=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/1999/xlink&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;216&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;96&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0 0 216 96&amp;quot;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;symbol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;zlg_logo&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            M  16  16&lt;/span&gt;
&lt;span class="s"&gt;            l  64   0&lt;/span&gt;
&lt;span class="s"&gt;            l -32  48&lt;/span&gt;
&lt;span class="s"&gt;            l  16   0&lt;/span&gt;
&lt;span class="s"&gt;            l  16  16&lt;/span&gt;
&lt;span class="s"&gt;            l -64   0&lt;/span&gt;
&lt;span class="s"&gt;            l  32 -48&lt;/span&gt;
&lt;span class="s"&gt;            l -16   0&lt;/span&gt;
&lt;span class="s"&gt;            Z&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            M  88 16&lt;/span&gt;
&lt;span class="s"&gt;            l  16 16&lt;/span&gt;
&lt;span class="s"&gt;            l   0 32&lt;/span&gt;
&lt;span class="s"&gt;            l  24  0&lt;/span&gt;
&lt;span class="s"&gt;            l  16 16&lt;/span&gt;
&lt;span class="s"&gt;            l -56  0&lt;/span&gt;
&lt;span class="s"&gt;            Z&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            M 200  16&lt;/span&gt;
&lt;span class="s"&gt;            l -16  16&lt;/span&gt;
&lt;span class="s"&gt;            l -16   0&lt;/span&gt;
&lt;span class="s"&gt;            c -22   0, -22  32, 0 32&lt;/span&gt;
&lt;span class="s"&gt;            l  16   0&lt;/span&gt;
&lt;span class="s"&gt;            l   0  -8&lt;/span&gt;
&lt;span class="s"&gt;            l  -8   0&lt;/span&gt;
&lt;span class="s"&gt;            l -16 -16&lt;/span&gt;
&lt;span class="s"&gt;            l  40   0&lt;/span&gt;
&lt;span class="s"&gt;            l   0  40&lt;/span&gt;
&lt;span class="s"&gt;            l -32   0&lt;/span&gt;
&lt;span class="s"&gt;            c -42   0, -42 -64, 0 -64&lt;/span&gt;
&lt;span class="s"&gt;            Z&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#zlg_logo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#zlg_logo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#000&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;x=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;y=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you save that and open it in your browser, you should see this &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt;
output:&lt;/p&gt;
&lt;object type="image/svg+xml"
data="https://zlg.space/blog/images/logo-dev/end-logo.svg" width="216px"
height="96px"&gt;&lt;/object&gt;

&lt;p&gt;Pretty slick, huh? &lt;sup id="fnref:xlink"&gt;&lt;a class="footnote-ref" href="#fn:xlink"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;Anatomy of an &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; file&lt;/h2&gt;
&lt;p&gt;&lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; files have a root container element (&lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;) that needs to tell the &lt;abbr title="eXtensible Markup Language"&gt;XML&lt;/abbr&gt;
parser what its namespace is, its dimensions, and the viewBox. For the sake of
simplicity, we'll say it's boilerplate. Inside this element is where all the fun
happens. This is nothing new if you've written any &lt;abbr title="eXtensible Markup Language"&gt;XML&lt;/abbr&gt;-based files before.&lt;/p&gt;
&lt;p&gt;Next, I created a &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; called "zlg_logo", which I'll refer to later.
Symbols are places where you can group shapes and paths, but &lt;em&gt;won't&lt;/em&gt; draw them
to the canvas automatically. The group element (&lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt;) groups while drawing, and
&lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; acts similar but is less semantic.&lt;/p&gt;
&lt;p&gt;A brief caveat: &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt;s need to be larger than the &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;s they're 
wrapping if you want to include effects like outlines or blurred shadows. 
Otherwise, the bounding box of the symbol will clip the drawing effect.&lt;/p&gt;
&lt;p&gt;Inside the symbol are three &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;s; they are the letters of the logo. I
could've added &lt;code&gt;id="Z"&lt;/code&gt; and so on to them, but it's unnecessary since they make
up one logical structure.&lt;/p&gt;
&lt;p&gt;At the end, I &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; the symbols and style them, much like I can in &lt;abbr title="HyperText Markup Language"&gt;HTML&lt;/abbr&gt;. The
division between &lt;code&gt;symbol&lt;/code&gt; and &lt;code&gt;use&lt;/code&gt; is similar to the division between &lt;abbr title="HyperText Markup Language"&gt;HTML&lt;/abbr&gt; and
&lt;abbr title="Cascading StyleSheets"&gt;CSS&lt;/abbr&gt;. You want the data (your paths, symbols, shapes, text) to be separate from
how you &lt;em&gt;present it&lt;/em&gt; (&lt;abbr title="Cascading StyleSheets"&gt;CSS&lt;/abbr&gt;, inline styling, &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The fun part is the &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; element. The &lt;code&gt;d&lt;/code&gt; attribute is short for "data". I
prefer to think of it as "directions" or "definition".&lt;/p&gt;
&lt;h3&gt;Path syntax&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; is possibly the most powerful element in &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt;. The &lt;code&gt;d&lt;/code&gt; attribute has a
sort of syntax. I separated each "command" by a new-line above to make it
clearer. &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; places little restriction on how you construct your paths. Each
"command" expects a certain number of arguments. To understand the commands, you
need to first understand the difference in case: &lt;code&gt;M&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; are two different
commands: uppercases work on &lt;em&gt;absolute&lt;/em&gt; coordinates, while lowercases work on
&lt;em&gt;relative&lt;/em&gt; coordinates. I prefer using relative coordinates inside a &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt;
element so I can move things around, resize, or transform them without having to
translate or edit the absolute coordinates inside the path. Your needs may
differ.&lt;/p&gt;
&lt;p&gt;So, in the first path (the "Z" glyph), the first command is to &lt;strong&gt;M&lt;/strong&gt;ove the
cursor to &lt;strong&gt;16,16&lt;/strong&gt;, from the top-left corner of the image. Then, draw a
&lt;strong&gt;l&lt;/strong&gt;ine going &lt;strong&gt;64&lt;/strong&gt; units to the right, and &lt;strong&gt;0&lt;/strong&gt; units vertically. The "Z"
glyph is a fairly simple shape, so the &lt;code&gt;l&lt;/code&gt; commands continue until I reach the
end, where the &lt;strong&gt;Z&lt;/strong&gt; command closes the shape with a straight line, skipping me
from writing out &lt;code&gt;l -16 -16&lt;/code&gt;. Lowercase &lt;strong&gt;z&lt;/strong&gt; does the same thing.&lt;/p&gt;
&lt;p&gt;Later in the file, I do &lt;strong&gt;c&lt;/strong&gt;ubic Bezier curves, which take three arguments:
the coordinates of the two curve handles, and the coordinates of the curve's end
point. If you're doing a relative &lt;code&gt;c&lt;/code&gt;, all coordinates are in relation to the
origin point of the curve!&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;With four "path verbs" inside three paths inside a single symbol, I've built
a logo that can be transformed, (re)colored, stretched, zoomed, embossed, and
more, without ever touching the commands that built it. Here are a few versions
that I came up with using only a few &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; elements:&lt;/p&gt;
&lt;object type="image/svg+xml" 
data="https://zlg.space/blog/images/logo-dev/assortment.svg" width="432" 
height="182"&gt;&lt;/object&gt;

&lt;p&gt;(Okay, I cheated and learned how gradients work for the last one.)&lt;/p&gt;
&lt;p&gt;There's a lot more to &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; than the brief bit that I've explored in this
post. Some people have made &lt;a href="http://tzdata-javascript.org/demos/analog_clock_2/analog_clock_2.html"&gt;real-time clocks&lt;/a&gt; (shout-out to
&lt;a href="https://mastodon.social/@stderr"&gt;stderr@mastodon.social&lt;/a&gt;), &lt;a href="https://web.archive.org/web/20131019072450/http://www.treebuilder.de/svg/connect4.svg"&gt;Connect Four
clones&lt;/a&gt;, and much more. I hope that what I've covered here has
helped demystify &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; a little bit and encouraged you to explore what text-based
vector formats can do for you.&lt;/p&gt;
&lt;p&gt;P.S. For comparison, my hand-written &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; file is under a &lt;abbr title="1,024 bytes (contrast to SI kilobyte of 1,000 bytes)"&gt;kibibyte&lt;/abbr&gt;, even with all
the extra whitespace. The Inkscape version was almost 5 &lt;abbr title="kibibytes"&gt;KiB&lt;/abbr&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:xlink"&gt;
&lt;p&gt;2018-09-07 - In a prior draft, the &lt;code&gt;xlink&lt;/code&gt; namespace wasn't included.
This breaks symbol linking in &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; 1.1 and below. In &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; 2, the xlink namespace
isn't needed. Both forms of linking are included for compatibility. I didn't
discover this until I tried to use an &lt;abbr title="Scalable Vector Graphics"&gt;SVG&lt;/abbr&gt; image as my avatar on the Fediverse.
It also didn't show up correctly in file previews. Be sure to include the
&lt;code&gt;xlink&lt;/code&gt; namespace if you plan to use the linking facilities!&amp;#160;&lt;a class="footnote-backref" href="#fnref:xlink" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Software"/><category term="SVG"/><category term="Inkscape"/><category term="XML"/><category term="Graphic Design"/></entry><entry><title>Say hello to vgstash!</title><link href="https://zlg.space/blog/say-hello-to-vgstash.html" rel="alternate"/><published>2016-05-22T22:27:00-07:00</published><updated>2025-09-25T00:46:00-07:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2016-05-22:/blog/say-hello-to-vgstash.html</id><summary type="html">&lt;p&gt;Today, I'm announcing the release of &lt;a href="https://git.zlg.space/vgstash"&gt;&lt;code&gt;vgstash&lt;/code&gt;&lt;/a&gt;, a command line program
that keeps track of your game collection and progress in a small SQLite
database. I'm happy to finally bring this to fruition. The story of its
inception follows.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Today, I'm announcing the release of &lt;a href="https://git.zlg.space/vgstash"&gt;&lt;code&gt;vgstash&lt;/code&gt;&lt;/a&gt;, a command line program
that keeps track of your game collection and progress in a small SQLite
database. I'm happy to finally bring this to fruition. The story of its
inception follows.&lt;/p&gt;


&lt;h1&gt;Inspiration&lt;/h1&gt;
&lt;p&gt;I was having a conversation on IRC about Python, lamenting my lack of project
ideas to learn the language better. During the conversation, I mentioned a game
manager I wanted to make, but I was hesitant to begin working on it until I
was sure I'd accounted for all semantic use cases. One person said, "What's
important to you about this tool?" That was the tipping point that got the ol'
gears turning. Why did I have this idea in the first place?&lt;/p&gt;
&lt;p&gt;I wanted a good way to manage my games without relying on an outside entity. Did
I care about it being a website? Not really; the mechanism didn't matter too
much to me as long as it worked. Did I really care if other people used it? Was
I interested in launching a website, building interest and engaging with the
public about it? Not really; socialization's never been my strong point, and I
wasn't ready for the consequences of gaining popularity: expectations, feature
requests, and considerable time to refine it.&lt;/p&gt;
&lt;p&gt;However, I strongly believe in the mantra of libre software: scratching your own
itch. So I identified the itch ("I need a game manager") and felt Python was a
great fit for it, since it comes with an SQLite3 module out of the box, a good
argument parsing module, and lots of options for data serialization. At that
point, the hard work was already done for me: &lt;em&gt;scope&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Implementation&lt;/h1&gt;
&lt;p&gt;Determining the scope of your project is important. It allows you to form
opinions on the data format it should rely on, which will help forge the path
for your implementation. This distinction is important; many programmers
approach it from a skeleton, a design document, or ad hoc. Some projects work
really well for that. Projects that deal with data storage and manipulation
(that is, most of them) should care very much about their data format. If you
nail the format, the rest of the code pretty much writes itself.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vgstash&lt;/code&gt;'s data format is as simple as I could make it without losing important
features. Nailing down this narrowed scope was almost liberating. My idea of
a game manager went from a grandiose Gordian knot of complexity to a command
line tool that plays nicely with others. &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; Because of this, I got a number
of features for free: simple searching (thanks to &lt;code&gt;grep&lt;/code&gt;), text manipulation
(&lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, and friends), and data serialization (pyyaml). This cut the
amount of time necessary to write the program, and it still supports everything
I aimed for. This simplicity assists in code maintenance; vgstash is nowhere
near complete or "correct", but it's important to do 80% of the job decently
than obsess over 100% perfection. Releasing a project and gaining attention
gives it momentum, and an incentive to continue development.&lt;/p&gt;
&lt;h1&gt;Usage&lt;/h1&gt;
&lt;p&gt;The documentation is still a bit rough for now. It works a lot like &lt;code&gt;git&lt;/code&gt; in
some ways. Here's a scenario (output is after a &lt;code&gt;&amp;gt;&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# I just picked up a game, let&amp;#39;s add it to my collection!&lt;/span&gt;
&lt;span class="c1"&gt;# It&amp;#39;s Dark Souls for the PS3&lt;/span&gt;
&lt;span class="c1"&gt;# I own it now, but I&amp;#39;ve never played it so it&amp;#39;s [f]resh.&lt;/span&gt;
&lt;span class="hll"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vgstash&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Dark Souls&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PS3&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;f
&lt;/span&gt;&lt;span class="c1"&gt;# &amp;gt; Added Dark Souls for PS3. You own it and it&amp;#39;s fresh.&lt;/span&gt;

&lt;span class="c1"&gt;# Show me a list of my games!&lt;/span&gt;
&lt;span class="hll"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vgstash&lt;span class="w"&gt; &lt;/span&gt;list
&lt;/span&gt;
&lt;span class="c1"&gt;# Okay I got a nice table, which ones have I beaten?&lt;/span&gt;
&lt;span class="hll"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vgstash&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;beaten
&lt;/span&gt;
&lt;span class="c1"&gt;# Nice, nice. Well, I just beat Dark Souls. What now?&lt;/span&gt;
&lt;span class="hll"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vgstash&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Dark Souls&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;|&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# &amp;gt; 45&lt;/span&gt;

&lt;span class="c1"&gt;# That gave me the game&amp;#39;s ID... Let&amp;#39;s update it&lt;/span&gt;
&lt;span class="hll"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vgstash&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;progress&lt;span class="w"&gt; &lt;/span&gt;b
&lt;/span&gt;&lt;span class="c1"&gt;# &amp;gt; Dark Souls on PS3 is now marked beaten.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You may notice that updating is a two-step process. You have to know the ID of
the game in order to update it. That's a ripe case for automation. vgstash was
designed to allow for that. In fact, I wrote a tentative shell script (found in
the repository) that will help you interactively update a game. Just give it an
argument to pass to &lt;code&gt;grep&lt;/code&gt; and it takes care of the rest.&lt;/p&gt;
&lt;h1&gt;Philosophy&lt;/h1&gt;
&lt;p&gt;Command line programs often use similar interfaces, and play nicely with piping.
Piping allows the user to bring out the full capability of the *nix environment
by treating programs as filters for text streams. It means programs are smaller
and more dedicated to a task. vgstash just stores your game collection and gives
you a set of commands to work with it. Other features (searching, interactively
updating, fancy interfaces, etc) should be handled by other programs, so users
can build and/or use scripting to their advantage. This phenomenon is known as
the UNIX philosophy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"Do one thing, and do it well."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That said, vgstash and any helper scripts in question are considered
experimental quality, so treat them accordingly.&lt;/p&gt;
&lt;p&gt;I'm extremely happy to have built this tool and hope that others find it useful,
too. Patches, comments, and suggestions are welcome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2022-09-04 UPDATE:&lt;/strong&gt; VGStash's CLI syntax has changed somewhat since the
announcement, and is available via PyPI! Visit the &lt;a href="https://pypi.org/project/vgstash"&gt;VGStash PyPI Project
Page&lt;/a&gt; for the latest release information.&lt;/p&gt;
&lt;p&gt;I have done some rudimentary testing on Windows and it appears to work in a
Command Prompt on Windows 7. I am in need of Windows-based testers, for cmd.eme,
PowerShell, MinGW, and/or WSL2. OS X users shouldn't have any issues interfacing
with VGStash, as long as pip's install path is somewhere in &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Well, ideally anyway. :)&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Software"/><category term="Python"/><category term="Video Games"/><category term="Command Line"/><category term="SQLite"/></entry><entry><title>Counting Lines of Code in Vim</title><link href="https://zlg.space/blog/counting-lines-of-code-in-vim.html" rel="alternate"/><published>2014-02-10T01:35:00-08:00</published><updated>2014-02-10T01:35:00-08:00</updated><author><name>zlg</name></author><id>tag:zlg.space,2014-02-10:/blog/counting-lines-of-code-in-vim.html</id><summary type="html">&lt;p&gt;Vim is a wonderfully extensible text editor. I use it to work with all sorts of
text. While I was browsing reddit, I saw a thread asking for a way to prevent
&lt;code&gt;:number&lt;/code&gt; from counting blank lines. I checked it out to see if there were any
cool answers. None of what I saw were adequate. For instance, &lt;code&gt;:%s/\S\+//n&lt;/code&gt;
makes every match highlight, clobbering the last text that was searched for.
I figured it was time for me to learn a little more about Vimscript, and so I
wrote a function that will tell you how many &lt;em&gt;actual lines of code&lt;/em&gt; are in your
file:&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Vim is a wonderfully extensible text editor. I use it to work with all sorts of
text. While I was browsing reddit, I saw a thread asking for a way to prevent
&lt;code&gt;:number&lt;/code&gt; from counting blank lines. I checked it out to see if there were any
cool answers. None of what I saw were adequate. For instance, &lt;code&gt;:%s/\S\+//n&lt;/code&gt;
makes every match highlight, clobbering the last text that was searched for.
I figured it was time for me to learn a little more about Vimscript, and so I
wrote a function that will tell you how many &lt;em&gt;actual lines of code&lt;/em&gt; are in your
file:&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;quot; Count the number of source lines in a file&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;SID&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;CountCodeLines&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; code_count &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; line &lt;span class="k"&gt;in&lt;/span&gt; getbufline&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;len&lt;span class="p"&gt;(&lt;/span&gt;line&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;line&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\S\+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;s:IsCommentLine&lt;span class="p"&gt;(&lt;/span&gt;line&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                continue
            &lt;span class="k"&gt;endif&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; code_count &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;endif&lt;/span&gt;
    &lt;span class="k"&gt;endfor&lt;/span&gt;
    echo code_count . &lt;span class="s1"&gt;&amp;#39; lines of code.&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="c"&gt;&amp;quot; To be used with CountCodeLines()&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; s:IsCommentLine&lt;span class="p"&gt;(&lt;/span&gt;line&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:comtypes &lt;span class="p"&gt;=&lt;/span&gt; []
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:comlist &lt;span class="p"&gt;=&lt;/span&gt; split&lt;span class="p"&gt;(&lt;/span&gt;&amp;amp;&lt;span class="nb"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; comlist
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:type &lt;span class="p"&gt;=&lt;/span&gt; split&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; len&lt;span class="p"&gt;(&lt;/span&gt;type&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;opt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; type[&lt;span class="m"&gt;1&lt;/span&gt;]
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;opt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; type[&lt;span class="m"&gt;0&lt;/span&gt;]
        &lt;span class="k"&gt;endif&lt;/span&gt;
        &lt;span class="k"&gt;call&lt;/span&gt; add&lt;span class="p"&gt;(&lt;/span&gt;comtypes&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;endfor&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; len&lt;span class="p"&gt;(&lt;/span&gt;comtypes&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;:line&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;^\s*&amp;#39;&lt;/span&gt; . escape&lt;span class="p"&gt;(&lt;/span&gt;comtypes[&lt;span class="k"&gt;i&lt;/span&gt;]&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/*&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;endif&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;endwhile&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Put that in your &lt;code&gt;~/.vimrc&lt;/code&gt; or another similar location and have at it! I chose 
to map it to &lt;code&gt;&amp;lt;leader&amp;gt;c&lt;/code&gt; with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nnoremap &amp;lt;leader&amp;gt;c :call &amp;lt;SID&amp;gt;CountCodeLines()&amp;lt;CR&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I'm releasing these functions under the &lt;a href="https://wtfpl.net/txt/copying"&gt;WTFPL&lt;/a&gt; to contribute another
mini-feature to Vim and the free, open source software community. It was a fun
(if slightly aggravating) exercise in Vimscript.&lt;/p&gt;</content><category term="Software"/><category term="vim"/></entry></feed>