Compare commits

...

2 commits

Author SHA1 Message Date
464f925c5c
new website 2025-09-26 21:42:27 -05:00
17e6bd38e3
Revamp of the website. 2025-02-15 15:52:15 -06:00
12 changed files with 670 additions and 654 deletions

View file

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>MIT License (GS Hosted)</title>
<meta name="author" content="pfm" />
<meta name="description" content="MIT License (GS Hosted)" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<div id="container">
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>Garrity Software</h1>
</header>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="license">
<h1>MIT License</h1>
<p>MIT License</p>
<p>Copyright [year] [name]</p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
<p>THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
</html>

View file

@ -1,160 +0,0 @@
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-size: 100%;
line-height: 1;
font-family: Roboto, sans-serif;
margin: 0;
padding: 0;
color: #000000;
}
a {
color: #0002cd;
}
a:visited {
color: #0002cd;
}
a:hover {
color: #333333;
text-decoration: none;
}
div#container {
width: 90ch;
margin-left: auto;
margin-right: auto;
}
header {
text-align: center;
}
header h1 {
font-size: 2.5rem;
font-family: Iosevka, monospace;
}
nav {
font-family: Iosevka, monospace;
font-size: 1.2rem;
background-color: #f6eeff;
padding: 0.5rem;
text-align: center;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
}
nav ul li {
display: inline-block;
margin: 0;
padding: 0;
}
nav ul li:not(:first-child) {
margin-left: 1rem;
}
nav a {
font-weight: 800;
}
main {
line-height: 1.25;
font-size: 1.1rem;
}
main a:hover {
color: #000;
box-shadow: 0 0 0 2px #2222cc;
}
main h1 {
padding: 0;
border-bottom: 1px dashed #333;
font-family: Mina, Iosevka, monospace;
font-size: 2rem;
}
main h2 {
padding: 0;
font-family: Mina, Iosevka, monospace;
font-size: 1.5rem;
}
dl {
padding: 1rem;
background-color: #f6f6f6;
}
dl dt {
font-weight: 800;
}
dl dt:not(:first-child) {
margin-top: 0.75rem;
}
dl dd {
margin: 0;
padding: 0;
}
footer {
margin-top: 1rem;
border-top: 1px solid #cccccc;
padding-top: 1rem;
margin-bottom: 1rem;
}
table, tr, td {
margin: 0;
padding: 0;
border: 0;
}
dl.project-list {
width: 100%;
font-size: 1rem;
padding: 0;
margin: 0;
background-color: #fff;
}
dl.project-list dt {
width: 100%;
margin-top: 1rem;
padding: 0.5rem;
display: block;
background-color: #f0f0f0;
border-top: 1px solid #999;
border-left: 1px solid #999;
border-right: 1px solid #999;
font-family: Iosevka, monospace;
}
dl.project-list dd {
width: 100%;
padding: 0.5rem;
border-bottom: 1px solid #999;
border-left: 1px solid #999;
border-right: 1px solid #999;
}
pre {
font-family: Iosevka, monospace;
font-size: 1rem;
color: #000;
padding: 0.5rem;
border: 1px solid #ccc;
}

View file

@ -1,56 +1,53 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>Garrity Software - Contact</title>
<meta name="author" content="pfm" />
<meta name="description" content="Garrity Software - Contact" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<head>
<title>Garrity Software - Contact</title>
<meta name="author" content="pfm" />
<meta name="description" content="garrity software contact information" />
<link rel="stylesheet" type="text/css" href="gs.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<header><a href="https://garrity.co">λ garrity software</a></header>
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="open-source.html">open source</a></li>
<li><a href="writing.html">writing</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<h1>Email</h1>
<p><code>pfm@garrity.co</code></p>
</section>
<div id="container">
<section>
<h1>Social Media</h1>
<p>I do not use any social media platforms.</p>
</section>
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>garrity software</h1>
</header>
<section>
<h1>Chat</h1>
<p>Email me for an invitation to the garrity-software
<a class="external" href="https://zulip.com/">Zulip</a> organization.
Zulip provides web and desktop clients.</p>
</section>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="contact">
<h1>Contact</h1>
<h2>Community Discord</h2>
<p><a href="https://discord.gg/nphkquBhw3">The Garrity Software Discord Community</a>
is intended to be a place to discuss and ask questions about open source
software, as well as discuss GS or software development in general. This Discord
server should not be used for product support.</p>
<p>This is also a viable option for getting in touch with Pat directly.</p>
<h2>Email</h2>
<p>pfm@garrity.co is an appropriate email address for reaching out to Pat
(the founder of Garrity Software) directly.</p>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
<section>
<h1>Git</h1>
<p>All source repositories are currently hosted under
<a class="external" href="https://git.garrity.co">git.garrity.co</a>
(my self-hosted <a class="external" href="https://forgejo.org/">Forgejo</a> instance),
though I may mirror open source repositories on
<a class="external" href="https://codeberg.org/">codeberg</a>.</p>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
</body>
</html>

View file

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Garrity Software - Donate</title>
<meta name="author" content="pfm" />
<meta name="description" content="Garrity Software - Donate" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<div id="container">
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>garrity software</h1>
</header>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="donate">
<h1>Donate</h1>
<p>Garrity Software is a fledgling organization that produces open source
libraries and intends to sell software. If you like the open source work, or you
want to support Pat in achieving the <a href="index.html#mission">Mission</a> of
a sustainable organization and lifestyle, please consider donating!</p>
<p><strong><a href="https://ko-fi.com/gspfm">Donate to Pat on Ko-fi</a></strong></p>
<h2>What do my donations do?</h2>
<p>Donations help to cover the costs of anything related to open source
development (servers, subscriptions, etc.) or community development. Donations
also serve as a general source of encouragement, and help move the needle
towards <em><a href="index.html#roadmap">independence</a></em>.</p>
<p>Donations are not (and will not be) used for any paid product hosting or
other payment-related services.</p>
</section>
<section id="sponsor">
<h1>Sponsorship</h1>
<p>If, for some reason, your company wants to <em>sponsor</em> Garrity Software,
please <a href="contact.html">contact Pat directly</a>.</p>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
</html>

220
src/gs.css Normal file
View file

@ -0,0 +1,220 @@
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html {
font-size: 16px;
}
body {
line-height: 1.2;
font-family: "Libre Baskerville", serif;
margin: 0;
padding: 0;
color: #000000;
}
::selection {
color: #f0f0f0;
background-color: #000000;
}
div#wrapper {
margin-top: 1rem;
margin-left: auto;
margin-right: auto;
width: 90ch;
}
header {
font-size: 1.15rem;
width: 100%;
text-align: center;
}
header a {
color: #000000;
display: inline-block;
text-decoration: none;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
header a:visited {
color: #000000;
}
header a:hover {
text-decoration: underline;
}
nav {
font-size: 1.25rem;
margin-top: 1rem;
margin-bottom: 1rem;
width: 100%;
background-color: #f6f6f6;
border: 1px solid #ccc;
text-align: center;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
}
nav ul li {
display: inline-block;
margin: 0;
padding: 0;
}
nav ul li:not(:first-child) {
margin-left: 0rem;
}
nav a {
color: #333333;
padding: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
display: inline-block;
text-decoration: none;
}
nav a:visited {
color: #333333;
}
nav a:hover {
background-color: #ffffff;
}
main {
font-size: 1.1rem;
}
footer {
font-size: 1rem;
margin-top: 3rem;
border-top: 1px solid #f0f0f0;
padding-top: 0.5rem;
text-align: center;
color: #666;
}
h1 {
font-size: 1.6rem;
font-family: Lato;
padding-bottom: 0.2rem;
border-bottom: 1px solid #e0e0e0;
display: block;
}
h2 {
font-size: 1.4rem;
font-family: Lato;
padding-bottom: 0.2rem;
border-bottom: 1px solid #e0e0e0;
display: block;
}
h3 {
font-size: 1.2rem;
font-family: Lato;
display: block;
}
span.focus {
font-variant: small-caps;
}
main a {
color: #444444;
}
main a:visited {
color: #000000;
}
main a:hover {
color: #777777;
}
main a.internal {
text-decoration: none;
border-bottom: 1px solid #333333;
padding-bottom: 0.1rem;
padding-top: 0;
}
main a.internal:hover {
color: #777777;
border-bottom: 1px solid #cccccc;
}
main a.external {
text-decoration: none;
border-bottom: 1px dotted #333333;
padding: 0.1rem;
padding-top: 0;
}
main a.external:hover {
color: #777777;
border-bottom: 1px dotted #cccccc;
}
ul#entry-list {
width: 100%;
list-style: none;
margin: 0;
padding: 0;
border: 1px solid #999999;
border-bottom: 0;
font-size: 1rem;
}
ul#entry-list li {
color: #222222;
display: block;
margin: 0;
padding: 1rem;
width: 100%;
border: 0;
border-bottom: 1px solid #999999;
transition: background 0.5s ease;
}
ul#entry-list li:hover {
border-bottom: 1px solid #999999;
background-color: #f0f0f0;
}
ul#entry-list a {
display: block;
padding: 0.5rem;
text-decoration: none;
}
ul#entry-list a:hover {
text-decoration: underline;
}
ul#entry-list li div.tags {
margin-left: 1rem;
display: inline-block;
}
small {
border-radius: 6px;
font-size: 0.8rem;
padding: 0.25rem;
color: #333333;
background-color: #cccccc;
border: 1px solid #cccccc;
display: inline-block;
}

View file

@ -1,131 +1,75 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>Garrity Software - About</title>
<meta name="author" content="pfm" />
<meta name="description" content="Garrity Software Homepage" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<head>
<title>Garrity Software</title>
<meta name="author" content="pfm" />
<meta name="description" content="garrity software homepage" />
<link rel="stylesheet" type="text/css" href="gs.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<header><a href="https://garrity.co">λ garrity software</a></header>
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="open-source.html">open source</a></li>
<li><a href="writing.html">writing</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<p><em>garrity software</em> (<span class="focus">gs</span>) is my software organization.
It is currently focused on open source projects and writing. It is
intended to one day develop software products.</p>
</section>
<div id="container">
<section>
<h1>Who Am I?</h1>
<p><span class="focus">pfm</span> [Pat] &mdash; Presumably human;
programming enthusiast and professional.</p>
</section>
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>garrity software</h1>
</header>
<section>
<h1>What I Do</h1>
<p><span class="focus">gs</span> produces libraries and
applications that support things I enjoy working on, such as
note taking, developer tooling, and software development;
I create libraries intended to be used in general settings.</p>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<p>For a list of <span class="focus">gs</span> projects,
please refer to <a class="internal" href="open-source.html">open source</a>.</p>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="short-description">
<p><em>Garrity Software</em> (GS) is a
<a href="#sustainable-organization">sustainable organization</a> devoted to
producing high quality, robust software. GS is also committed to contributing
open source work and releasing as much software for free as possible. GS is
currently <a href="#roadmap"><em>Bootstrapping</em></a>, does not have income,
and is primarily producing <a href="oss.html">open source libraries</a>.</p></section>
<p>I also <a class="internal" href="writing.html">write</a> about software from time to time.</p>
<section id="mission">
<h1>Mission</h1>
<p>Garrity Software aims to produce high quality software to solve a variety of
problems. At the same time, it aims to remain small in size and provide a stable
living for a small number of people, enabling them to work less, spend time with
their families, and pursue their own interests. Finally, GS aims to provide open
source software and to financially support open source development.</p>
<h2>Languages &amp; Ecosystems</h2>
<p>I primarily work in
<a class="external" href="https://scala-lang.org/">Scala 3</a>,
leveraging the <a class="external" href="https://typelevel.org/cats/">Cats</a> ecosystem.</p>
<h2 id="donations">Donations</h2>
<p>If you want to support the GS mission or open source work, please consider
<a href="donate.html">donating</a> to the founder.</p>
<h2>My Development Approach</h2>
<p>I strive to write <em>robust</em> code that meets its goals and stands the test of time.
I enjoy rapid iteration backed by thought and preparation. I work best when I'm having fun,
and work best when I'm working on an interesting problem.</p>
</section>
<h2 id="roadmap">Roadmap and Progress</h2>
<p>The GS vision is non-trivial to achieve. Quality open source projects are a
starting point, but supporting employees and open source projects requires
products and income. GS has a coarse-grained roadmap towards the mission.</p>
<section>
<h1>My Goals</h1>
<p>One day I hope to commit entirely to <span class="focus">gs</span>, producing software
and documentation that I find useful, releasing as much as possible for free. My minimum
runway to this end appears to be 2030 - I expect it to be further in the future, and the
ultimate timeline depends on my family and what I can scrape together at night. In the
meantime, my goal is to keep coding in my free time and preserve my love for my craft.</p>
<p>Current Status: <strong>Bootstrapping</strong></p>
<p>Current Estimate: <strong>Behind!</strong></p>
<p>Development continues, but limited time means limited progress. Likely will
need to adjust schedule to spend more time on baseline development.</p>
<dl>
<dt>Bootstrapping (2024)</dt>
<dd>Establish open source libraries and build the first product. Establish
Garrity Software as an LLC.</dd>
<dt>Initial Sales (By June 2025)</dt>
<dd>Start attempting to sell software.</dd>
<dt>Independence (By 2030)</dt>
<dd>Founder achieves ability to stop working for other companies. Requires
income from all sources to be sufficient to support family.</dd>
<dt>First External Hire</dt>
<dd>Another person is hired. That person is fully compensated.</dd>
<dt>Hire to Five</dt>
<dd>Bring in additional people until the arbitrary threshold of five
employees is met.</dd>
<dt>Sustain</dt>
<dd>Hit a balance point that supports year-to-year stability in line with
the GS mission.</dd>
</dl>
</section>
<section id="sustainable-organization">
<h1>Sustainable Organization</h1>
<h2>Sustainability</h2>
<p>Garrity Software is based on the premise of sustainability. This is measured
in terms of employee needs and company performance. The goal is a balance where
GS earns enough to support a small number of employees that do not need to work
a full week. To achieve this goal, GS needs to earn enough money and have stable
enough products. At the same time, GS needs to resist unbounded growth and
becoming too large. The steady state should have employees that can both
maintain current products and pursue new work without needing to put in extra
time.</p>
<h2>Execution</h2>
<ul>
<li>Establish strong core products that produce reliable income.</li>
<li>Never allow the organization to become beholden to external investors.</li>
<li>Do not spend money that GS does not have.</li>
<li>Limit staff to five total employees.</li>
<li>Establish four day work weeks starting with the first hire.</li>
<li>Ensure that hiring only starts when enough income exists to support a comfortable living wage (including things like health care) for any hired person.</li>
<li>Establish a fund to donate to, or otherwise support, open source development.</li>
</ul>
</section>
<section id="team">
<h1>Team</h1>
<h2>Pat Garrity (pfm)</h2>
<p>Founder and visionary of Garrity Software.</p>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
<p>If you want to support my goals, discuss software with me in my <a href="contact.html">Zulip organization</a> or
<a class="external" href="https://ko-fi.com/gspfm">donate</a> if you find my contributions useful and are
in a position to do so.</p>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
</body>
</html>

64
src/open-source.html Normal file
View file

@ -0,0 +1,64 @@
<!doctype html>
<html>
<head>
<title>Garrity Software - Open Source</title>
<meta name="author" content="pfm" />
<meta name="description" content="garrity software open source" />
<link rel="stylesheet" type="text/css" href="gs.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<header><a href="https://garrity.co">λ garrity software</a></header>
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="open-source.html">open source</a></li>
<li><a href="writing.html">writing</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<ul id="entry-list">
<li>
<a href="https://git.garrity.co/garrity-software/gs-uuid">gs-uuid</a>
<div class="tags">
<small>2025-07-23</small>
<small>scala</small>
<small>library</small>
</div>
</li>
<li>
<a href="https://git.garrity.co/garrity-software/gs-timing">gs-timing</a>
<div class="tags">
<small>2025-07-23</small>
<small>scala</small>
<small>library</small>
</div>
</li>
<li>
<a href="https://git.garrity.co/garrity-software/gs-datagen">gs-datagen</a>
<div class="tags">
<small>2025-07-23</small>
<small>scala</small>
<small>library</small>
</div>
</li>
<li>
<a href="https://git.garrity.co/garrity-software/gs-config">gs-config</a>
<div class="tags">
<small>2025-07-23</small>
<small>scala</small>
<small>library</small>
</div>
</li>
</ul>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
</body>
</html>

View file

@ -1,153 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Garrity Software - Open Source</title>
<meta name="author" content="pfm" />
<meta name="description" content="Garrity Software - Open Source" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<div id="container">
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>garrity software</h1>
</header>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="open-source">
<h1>Open Source</h1>
<p>Garrity Software exposes all non-product software as open source. Typically,
either the MIT License or the Apache 2.0 license is used.</p>
<p>If you have questions or want to discuss these projects, consider joining the
<a href="https://discord.gg/nphkquBhw3">Garrity Software Discord Community</a>.</p>
</section>
<section id="scala">
<h2>Scala</h2>
<p>All GS projects are currently implemented in Scala 3. No Scala 2 artifacts
are available. GS typically leans towards the newest available Scala versions.
GS libraries typically try to minimize size and dependency scope.</p>
<p>GS does not yet build libraries for Scala Native or ScalaJS.</p>
</section>
<section id="vcs">
<h2>Version Control (Git)</h2>
<p>GS uses self-hosted version control at
<a href="https://git.garrity.co/garrity-software">https://git.garrity.co/garrity-software</a>.
All code is available, though registration is not available at this time. Once
all setup is complete, accounts may be granted to allow for contributions.</p>
<h3>Mirrors</h3>
<p>Mirrors do not yet exist, but are planned. Mirrors will be available on GitHub.</p>
</section>
<section id="maven">
<h2>Maven</h2>
<p>GS provides a Maven server and does not upload artifacts to other public
Maven/Ivy repositories at this time.</p>
<pre><code>resolvers += "garrity-software-gs" at "https://maven.garrity.co/gs"</code></pre>
<p>No credentials are required to use this repository.</p>
</section>
<section id="api-docs">
<h2>API Documentation</h2>
<p>ScalaDoc is not yet published.</p>
</section>
<section id="projects">
<h2>Projects</h2>
<dl class="project-list">
<dt><a href="https://git.garrity.co/garrity-software/gs-uuid">gs-uuid</a>
(Scala 3) (Library)</dt>
<dd>Uses <a href="https://github.com/cowtowncoder/java-uuid-generator/">JUG</a>
and ported code from Jackson to provide an opaque <code>UUID</code> type
over <code>java.util.UUID</code>, backed by custom rendering and parsing.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-slug">gs-slug</a>
(Scala 3) (Library)</dt>
<dd>Provides a <code>Slug</code> type. This type relies on a very small set of
ASCII characters and is intended for URL-safe identifiers.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-hex">gs-hex</a>
(Scala 3) (Library)</dt>
<dd>Small, efficient, Hexadecimal conversion library with encoder/decoder type
classes and support for basic types. Based on handling byte arrays.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-blob">gs-blob</a>
(Scala 3) (Library)</dt>
<dd>Opaque type (<code>Blob</code>) and tools (e.g. encoding) for "blobs" -
arrays of bytes.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-datagen">gs-datagen</a>
(Scala 3) (Library)</dt>
<dd>Random data generation library for Scala 3. Intended for use in tests, but
not limited to that case. Provides a composable type for generators and
several standard generators.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-config">gs-config</a>
(Scala 3) (Library)</dt>
<dd>Library for loading, and specifically <em>auditing</em>, configuration.
Provides a complete digest of what configuration keys were queried and what
happened to them.</dd>
</dl>
</section>
<section id="incubator">
<h2>Incubator</h2>
<dl class="project-list">
<dt><a href="https://git.garrity.co/garrity-software/gs-test">gs-test</a>
(Scala 3) (Library)</dt>
<dd>Test framework for Scala 3. Based on Cats Effect. Notably provides
structured test output and envisions a more powerful method of expressing
test execution.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-log">gs-log</a>
(Scala 3) (Library)</dt>
<dd>FP logging library for Scala 3.</dd>
<dt><a href="https://git.garrity.co/garrity-software/gs-crypto">gs-crypto</a>
(Scala 3) (Library)</dt>
<dd>Based on JVM standard implementations and Bouncy Castle. Working to define
some crypto interfaces for GS projects in a way that works well with
Scala.</dd>
<dt><a href="https://git.garrity.co/garrity-software/smolban">smolban</a>
(Scala 3) (Application)</dt>
<dd>Fun side-project to create a small/minimal Kanban oriented system. Light on
process, helps prove out certain concepts in a non-critical
application.</dd>
</dl>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
</html>

View file

@ -1,48 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Garrity Software - Products</title>
<meta name="author" content="pfm" />
<meta name="description" content="Garrity Software - Products" />
<link rel="stylesheet" type="text/css" href="assets/gs.css">
</head>
<body>
<div id="container">
<!-- Header/Logo -------------------------------------------------------------->
<header>
<h1>garrity software</h1>
</header>
<!-- Navigation --------------------------------------------------------------->
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="products.html">products</a></li>
<li><a href="oss.html">open source</a></li>
<li><a href="donate.html">donate</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<!-- Main Content ------------------------------------------------------------->
<main>
<section id="products">
<h1>Products</h1>
<p>Garrity Software is <a href="index.html#roadmap">Bootstrapping</a> and does
not yet offer any products.</p>
</section>
</main>
<!-- Footer ------------------------------------------------------------------->
<footer>
Content Copyright © Patrick Garrity
</footer>
</div>
</body>
</html>

40
src/writing.html Normal file
View file

@ -0,0 +1,40 @@
<!doctype html>
<html>
<head>
<title>Garrity Software - Writing</title>
<meta name="author" content="pfm" />
<meta name="description" content="garrity software writing" />
<link rel="stylesheet" type="text/css" href="gs.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<header><a href="https://garrity.co">λ garrity software</a></header>
<nav>
<ul>
<li><a href="index.html">about</a></li>
<li><a href="open-source.html">open source</a></li>
<li><a href="writing.html">writing</a></li>
<li><a href="contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<ul id="entry-list">
<li>
<a href="writing/semantic-type-refinement.html">Semantic Type Refinement</a>
<div class="tags">
<small>2025-09-25</small>
<small>scala</small>
<small>types</small>
</div>
</li>
</ul>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
</body>
</html>

View file

@ -0,0 +1,73 @@
<!doctype html>
<html>
<head>
<title>Garrity Software - Optimizing Shell History</title>
<meta name="author" content="pfm" />
<meta name="description" content="writing - optimizing shell history" />
<link rel="stylesheet" type="text/css" href="../gs.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js"></script>
</head>
<body>
<div id="wrapper">
<header><a href="#">λ garrity software</a></header>
<nav>
<ul>
<li><a href="../index.html">about</a></li>
<li><a href="../open-source.html">open source</a></li>
<li><a href="../writing.html">writing</a></li>
<li><a href="../contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<h1>Optimizing Shell History</h1>
<p>I've spent a lot of time fiddling with my local development environment over
the years. As a result, I've also evolved how I interact with my shell history.</p>
<p>I would say that I use my history as a convenience and efficiency booster,
though I do not use it to drive workflow to the extent I see from others.</p>
<p>I take advantage of three things:</p>
<ol>
<li>History configuration settings.</li>
<li>Shell comments.</li>
<li>Fuzzy search (FZF, in this case).</li>
</ol>
</section>
<section>
<h2 id="history-configuration">History Configuration</h2>
<p>I currently use <code>zsh</code>, so the example below is
for <code>zsh</code>.</p>
<pre><code class="language-bash">export HISTFILE="$HOME/.zsh_history"
export HISTSIZE=25000
export SAVEHIST=$HISTSIZE
export HISTORY_IGNORE="(ls|cd|pwd|exit)*"
setopt EXTENDED_HISTORY # Write the history file in the ':start:elapsed;command' format.
setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
setopt SHARE_HISTORY # Share history between all sessions.
setopt HIST_IGNORE_DUPS # Do not record an event that was just recorded again.
setopt HIST_IGNORE_ALL_DUPS # Delete an old recorded event if a new event is a duplicate.
setopt HIST_IGNORE_SPACE # Do not record an event starting with a space.
setopt HIST_SAVE_NO_DUPS # Do not write a duplicate event to the history file.
setopt HIST_VERIFY # Do not execute immediately upon history expansion.
setopt APPEND_HISTORY # append to history file (Default)
setopt HIST_NO_STORE # Don't store history commands
setopt HIST_REDUCE_BLANKS # Remove superfluous blanks from each command line being added to the history.
setopt INTERACTIVE_COMMENTS # Allow comments in interactive shell.
# Example of what I have - you can use your own configuration. Note that this
# example is intended for use on wayland with wl-copy.
export FZF_CTRL_R_OPTS="
--preview 'echo {}' --preview-window up:3:hidden:wrap
--bind 'ctrl-/:toggle-preview'
--bind 'ctrl-y:execute-silent(echo -n {2..} | wl-copy)+abort'
--color header:italic
--header 'Press CTRL-Y to copy command into clipboard'"</code></pre>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
<script>hljs.highlightAll();</script>
</body>
</html>

View file

@ -0,0 +1,160 @@
<!doctype html>
<html>
<head>
<title>Semantic Type Refinement (GS)</title>
<meta name="author" content="pfm" />
<meta name="description" content="semantic type refinement" />
<link rel="stylesheet" type="text/css" href="../gs.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/scala.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<header><a href="https://garrity.co">λ garrity software</a></header>
<nav>
<ul>
<li><a href="../index.html">about</a></li>
<li><a href="../open-source.html">open source</a></li>
<li><a href="../writing.html">writing</a></li>
<li><a href="../contact.html">contact</a></li>
</ul>
</nav>
<main>
<section>
<h1>Semantic Type Refinement</h1>
<p>Types can be great. In the context of Scala, I like using types heavily.
They help me think and write better code more quickly. The notion of <em>refined types</em>
is a way to leverage types to enforce certain constraints - often at compile time.</p>
<p>Excellent libraries such as
<a class="external" href="https://github.com/fthomas/refined">refined</a>
have an obvious introductory example:</p>
<pre><code class="language-scala">scala> val i2: Int Refined Positive = -5
error: Predicate failed: (-5 > 0).</code></pre>
<p>To be clear: this is great! I want to talk about another way to refine types
without taking away from the standard case.</p>
</section>
<section>
<h2 id="another-approach-to-refinement">Another Approach to Refinement</h2>
<p>The basic refinement example essentially makes the type more specific. Another way to look
at it is that it removes unwanted values from the range of possible values. Rather than a
type that accepts integers, we have a type which only accepts <em>positive</em> integers.</p>
<p>This is useful, though in many context I prefer to go further. At the end of the day,
with this example, I just have a positive integer. What is the purpose of that integer?
Adding specific semantics to a type can make it <em>stronger</em> and <em>more meaningful</em>.</p>
<p>Let's pretend that our positive integer is actually intended to express some configurable
maximum concurrency value (please bear with the exception for now):</p>
<pre><code class="language-scala">opaque type MaximumConcurrency = Int
object MaximumConcurrency:
def apply(candidate: Int): MaximumConcurrency =
if candidate <= 0 then
throw new IllegalArgumentException(
"Maximum concurrency must be 1 or greater."
)
else candidate
given CanEqual[MaximumConcurrency, MaximumConcurrency] = CanEqual.derived
extension (mc: MaximumConcurrency) def toInt(): Int = mc
end MaximumConcurrency</code></pre>
<p>While this involves slightly more typing, it has several benefits:</p>
<ul>
<li><code>MaximumConcurrency</code> obviously describes the purpose of the type.</li>
<li>The type can be independently documented.</li>
<li>Some value of this type can only be equated to other <code>MaximumConcurrency</code> values.</li>
<li>Logic and functions can be contextualized to this type.</li>
<li>Values of this type cannot exist unless they meet validation criteria.</li>
<li>Zero dependencies.</li>
</ul>
<p>Lest we forget the drawbacks:</p>
<ul>
<li>Value validation does not occur at compile time.</li>
<li>Implementation is manual.</li>
</ul>
</section>
<section>
<h2 id="addressing-drawbacks">Addressing Drawbacks</h2>
<p>First off: many values are <em>not</em> known at compile time. Refinement libraries
are not unaware of this, and provide tools for refining at runtime.</p>
<p>Manual implementation simply does not bother me -- it is a small effort, and that
effort <em>forces</em> me to think about each type and document each type. I am also forced
to <em>justify</em> a <em>purpose</em> for each type. I spend more time thinking, and less
time actually writing; a common theme with specific types.</p>
<p>That being said, this approach isn't for everything. Sometimes there are literals that
just need to be non-semantic, because trying to apply that layer has no value. That's okay,
and lines need to be drawn.</p>
</section>
<section>
<h2 id="what-about-exceptions">What About Exceptions?</h2>
<p>There is no reason a type <em>must</em> rely on exceptions to perform validation:</p>
<pre><code class="language-scala">opaque type MaximumConcurrency = Int
object MaximumConcurrency:
def validate(candidate: Int): Either[MyError, MaximumConcurrency] =
if candidate <= 0 then Left(MyError.InvalidMaximumConcurrency(candidate))
else candidate</code></pre>
<p>Refinement of the type can be catered to the case at hand. Use whatever mechanism
best fits the type.</p>
</section>
<section>
<h2 id="types-without-validation">Types Without Validation</h2>
<p>This same approach can be used to give type restrictions to unconstrained values:</p>
<pre><code class="language-scala">opaque type MaximumConcurrency = Int
object MaximumConcurrency:
def apply(value: Int): MaximumConcurrency = value</code></pre>
<p>Opaque type aliases are a technique that I use often, as these types still
prevent the use of mismatched types and communicate valuable information.</p>
</section>
<section>
<h2 id="summary">Summary</h2>
<p>Restrictions are often power, and clarity is also often power. I enjoy both,
and make heavy use of them in my code. In general, I tend to rely on a dependency-free
manual approach to refining my types in a way that forces me to justify the existence
of every single type - I think the approach is at least worth consideration. I think
that libraries which solve a general case well are valuable in their own right and hope
that this brief writeup is not taken as a reason to avoid them.</p>
<p>I particularly like the inclusion of <code>opaque</code> types in Scala 3 and use
them heavily in lieu of fundamental types.</p>
</section>
</main>
<footer>Copyright <span class="focus">pfm</span></footer>
</div>
<script>hljs.highlightAll();</script>
</body>
</html>