Commit 7d3b5175f2

7d3b5175f2d9d016b06190273fcfeb380a460b3f

parent: 7c70a351e2

Unsigned

cmc <hello@cleberg.net> · 2024-05-02 02:45 UTC

prettier formatting and rewrap lines

Layout: unified · split

README.md +6 −11
@@ -2,15 +2,18 @@
2 2
3[cleberg.net](https://cleberg.net) is my personal webpage. 3[cleberg.net](https://cleberg.net) is my personal webpage.
4 4
5This README is viewable on [git.cleberg.net](https://git.cleberg.net/?p=cleberg.net.git;a=blob;f=README.org;h=155f4696a09503411730afc422b7fb49acbef8f3;hb=HEAD). 5This README is viewable on
6[git.cleberg.net](https://git.cleberg.net/?p=cleberg.net.git;a=blob;f=README.org;h=155f4696a09503411730afc422b7fb49acbef8f3;hb=HEAD).
6 7
7## Overview 8## Overview
8 9
9This website & blog uses [Markdown](https://spec.commonmark.org/current/), published with [Zola](https://www.getzola.org/). 10This website & blog uses [Markdown](https://spec.commonmark.org/current/),
11published with [Zola](https://www.getzola.org/).
10 12
11## Configuration 13## Configuration
12 14
13All configuration options are available within the `config.toml` file. Refer to the Zola documentation for further configuration options. 15All configuration options are available within the `config.toml` file. Refer to
16the Zola documentation for further configuration options.
14 17
15## Building 18## Building
16 19
@@ -28,13 +31,5 @@ Use `zola build` and deploy to whichever deployment target you prefer.
28 31
29## Tasks 32## Tasks
30 33
31- [x] Format all blog posts
32 - [x] 2018
33 - [x] 2019
34 - [x] 2020
35 - [x] 2021
36 - [x] 2022
37 - [x] 2023
38 - [x] 2024
39- [ ] Add descriptions to blog posts 34- [ ] Add descriptions to blog posts
40- [ ] Figure out how to get file tags to show up 35- [ ] Figure out how to get file tags to show up
content/blog/2018-11-28-aes-encryption.md +9 −10
@@ -13,8 +13,7 @@ If you're not familiar with encryption techniques,
13National Institute of Standards and Technology, sub-selected from the Rijndael 13National Institute of Standards and Technology, sub-selected from the Rijndael
14family of ciphers (128, 192, and 256 bits) in 2001. Furthering its popularity 14family of ciphers (128, 192, and 256 bits) in 2001. Furthering its popularity
15and status, the US government chose AES as their default encryption method for 15and status, the US government chose AES as their default encryption method for
16top-secret data, removing the previous standard which had been in place since 16top-secret data, removing the previous standard which had been in place since 1977.
171977.
18 17
19AES has proven to be an extremely safe encryption method, with 7-round and 18AES has proven to be an extremely safe encryption method, with 7-round and
208-round attacks making no material improvements since the release of this 198-round attacks making no material improvements since the release of this
@@ -24,8 +23,8 @@ encryption standard almost two decades ago.
24> fastest single-key attacks on round-reduced AES variants [20, 33] so far are 23> fastest single-key attacks on round-reduced AES variants [20, 33] so far are
25> only slightly more powerful than those proposed 10 years ago [23,24]. 24> only slightly more powerful than those proposed 10 years ago [23,24].
26> 25>
27> - [Bogdonav, et 26> - [Bogdonav, et
28> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf) 27> al.](http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf)
29 28
30# How Secure is AES? 29# How Secure is AES?
31 30
@@ -99,8 +98,8 @@ where feasible:
991. Privacy is a human right and is recognized as a national right in some 981. Privacy is a human right and is recognized as a national right in some
100 countries (e.g., [US Fourth 99 countries (e.g., [US Fourth
101 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)). 100 Amendment](https://www.law.cornell.edu/wex/fourth_amendment)).
1022. "Why not?" Encryption rarely affects performance or speed, so there's 1012. "Why not?" Encryption rarely affects performance or speed, so there's usually
103 usually not a reason to avoid it in the first place. 102 not a reason to avoid it in the first place.
1043. Your digital identity and activity (texts, emails, phone calls, online 1033. Your digital identity and activity (texts, emails, phone calls, online
105 accounts, etc.) are extremely valuable and can result in terrible 104 accounts, etc.) are extremely valuable and can result in terrible
106 consequences, such as identity theft, if leaked to other parties. Encrypting 105 consequences, such as identity theft, if leaked to other parties. Encrypting
@@ -110,10 +109,10 @@ where feasible:
110 devices. 109 devices.
1115. Corporations, governments, and other nefarious groups/individuals are 1105. Corporations, governments, and other nefarious groups/individuals are
112 actively looking for ways to collect personal information about anyone they 111 actively looking for ways to collect personal information about anyone they
113 can. If someone's data is unencrypted, that person may become a target due 112 can. If someone's data is unencrypted, that person may become a target due to
114 to the ease of data collection. 113 the ease of data collection.
115 114
116​**Read More:** 115​**Read More:**
117 116
118- [Federal Information Processing Standards Publication 117- [Federal Information Processing Standards Publication
119 197](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf) 118 197](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf)
content/blog/2018-11-28-cpp-compiler.md +2 −2
@@ -16,7 +16,7 @@ executed. There are many steps and intricacies to the compilation process, and
16this post was a personal exercise to learn and remember as much information as I 16this post was a personal exercise to learn and remember as much information as I
17can. 17can.
18 18
19``` cpp 19```cpp
20#include <iostream> 20#include <iostream>
21 21
22int main() 22int main()
@@ -76,7 +76,7 @@ dynamically.
76For example, the `Hello, world!` code snippet above compiles into the following 76For example, the `Hello, world!` code snippet above compiles into the following
77assembly code: 77assembly code:
78 78
79``` asm 79```asm
80.LC0: 80.LC0:
81 .string "Hello, world!\n" 81 .string "Hello, world!\n"
82main: 82main:
content/blog/2019-01-07-useful-css.md +61 −61
@@ -34,15 +34,15 @@ extended, where extra variables could be defined for `primary-text`,
34For example, here are some variables defined at the root of the website, which 34For example, here are some variables defined at the root of the website, which
35allows for any subsequent CSS rules to use those variables: 35allows for any subsequent CSS rules to use those variables:
36 36
37``` css 37```css
38:root { 38:root {
39 --primary-color: black; 39 --primary-color: black;
40 --secondary-color: white; 40 --secondary-color: white;
41} 41}
42 42
43body { 43body {
44 background-color: var(--primary-color); 44 background-color: var(--primary-color);
45 color: var(--secondary-color); 45 color: var(--secondary-color);
46} 46}
47``` 47```
48 48
@@ -50,14 +50,14 @@ body {
50 50
51Box shadows were once my mortal enemy. No matter how hard I tried, I just 51Box shadows were once my mortal enemy. No matter how hard I tried, I just
52couldn't get them to work how I wanted. Because of this, my favorite discovery 52couldn't get them to work how I wanted. Because of this, my favorite discovery
53has been CSSMatic's [box shadow 53has been CSSMatic's [box shadow generator](https://www.cssmatic.com/box-shadow).
54generator](https://www.cssmatic.com/box-shadow). It provides an excellent tool 54It provides an excellent tool to generate box shadows using their simple
55to generate box shadows using their simple sliders. Surprisingly, this is the 55sliders. Surprisingly, this is the reason I learned how box shadows work! You
56reason I learned how box shadows work! You can use the sliders and watch how the 56can use the sliders and watch how the CSS code changes in the image that is
57CSS code changes in the image that is displayed. Through this, you should 57displayed. Through this, you should understand that the basic structure for box
58understand that the basic structure for box shadows is: 58shadows is:
59 59
60``` css 60```css
61box-shadow: inset horizontal vertical blur spread color; 61box-shadow: inset horizontal vertical blur spread color;
62``` 62```
63 63
@@ -67,55 +67,55 @@ with the code, experiment, and learn.
67 67
68**Box Shadow #1** 68**Box Shadow #1**
69 69
70``` html 70```html
71<div class="shadow-examples"> 71<div class="shadow-examples">
72 <div class="box effect1"> 72 <div class="box effect1">
73 <h3>Effect 1</h3> 73 <h3>Effect 1</h3>
74 </div> 74 </div>
75</div> 75</div>
76``` 76```
77 77
78``` css 78```css
79.box h3 { 79.box h3 {
80 text-align: center; 80 text-align: center;
81 position: relative; 81 position: relative;
82 top: 80px; 82 top: 80px;
83} 83}
84.box { 84.box {
85 width: 70%; 85 width: 70%;
86 height: 200px; 86 height: 200px;
87 background: #fff; 87 background: #fff;
88 margin: 40px auto; 88 margin: 40px auto;
89} 89}
90.effect1 { 90.effect1 {
91 box-shadow: 0 10px 6px -6px #777; 91 box-shadow: 0 10px 6px -6px #777;
92} 92}
93``` 93```
94 94
95**Box Shadow #2** 95**Box Shadow #2**
96 96
97``` html 97```html
98<div class="shadow-examples"> 98<div class="shadow-examples">
99 <div class="box effect2"> 99 <div class="box effect2">
100 <h3>Effect 2</h3> 100 <h3>Effect 2</h3>
101 </div> 101 </div>
102</div> 102</div>
103``` 103```
104 104
105``` css 105```css
106.box h3 { 106.box h3 {
107 text-align: center; 107 text-align: center;
108 position: relative; 108 position: relative;
109 top: 80px; 109 top: 80px;
110} 110}
111.box { 111.box {
112 width: 70%; 112 width: 70%;
113 height: 200px; 113 height: 200px;
114 background: #fff; 114 background: #fff;
115 margin: 40px auto; 115 margin: 40px auto;
116} 116}
117.effect2 { 117.effect2 {
118 box-shadow: 10px 10px 5px -5px rgba(0, 0, 0, 0.75); 118 box-shadow: 10px 10px 5px -5px rgba(0, 0, 0, 0.75);
119} 119}
120``` 120```
121 121
@@ -128,7 +128,7 @@ Now, let's move on to the best part of this article: flexbox. The flexbox is by
128far my favorite new toy. I originally stumbled across this solution after 128far my favorite new toy. I originally stumbled across this solution after
129looking for more efficient ways of centering content horizontally AND 129looking for more efficient ways of centering content horizontally AND
130vertically. I had used a few hack-ish methods before, but flexbox throws those 130vertically. I had used a few hack-ish methods before, but flexbox throws those
131out the window. The best part of it all is that flexbox is *dead simple*. 131out the window. The best part of it all is that flexbox is _dead simple_.
132 132
133Flexbox pertains to the parent div of any element. You want the parent to be the 133Flexbox pertains to the parent div of any element. You want the parent to be the
134flexbox in which items are arranged to use the flex methods. It's easier to see 134flexbox in which items are arranged to use the flex methods. It's easier to see
@@ -136,34 +136,34 @@ this in action that explained, so let's see an example.
136 136
137**Flexbox** 137**Flexbox**
138 138
139``` html 139```html
140<div class="flex-examples"> 140<div class="flex-examples">
141 <div class="sm-box"> 141 <div class="sm-box">
142 <h3>1</h3> 142 <h3>1</h3>
143 </div> 143 </div>
144 <div class="sm-box"> 144 <div class="sm-box">
145 <h3>2</h3> 145 <h3>2</h3>
146 </div> 146 </div>
147</div> 147</div>
148``` 148```
149 149
150``` css 150```css
151.flex-examples { 151.flex-examples {
152 display: flex; 152 display: flex;
153 flex-wrap: wrap; 153 flex-wrap: wrap;
154 justify-content: flex-start; 154 justify-content: flex-start;
155 align-items: center; 155 align-items: center;
156 padding: 10px; 156 padding: 10px;
157 background-color: #f2f2f2; 157 background-color: #f2f2f2;
158} 158}
159.sm-box { 159.sm-box {
160 display: flex; 160 display: flex;
161 justify-content: center; 161 justify-content: center;
162 align-items: center; 162 align-items: center;
163 width: 20%; 163 width: 20%;
164 height: 100px; 164 height: 100px;
165 background: #fff; 165 background: #fff;
166 margin: 40px 10px; 166 margin: 40px 10px;
167} 167}
168``` 168```
169 169
content/blog/2019-09-09-audit-analytics.md +29 −30
@@ -23,10 +23,10 @@ One of the common mistakes that managers (and anyone new to the process) make is
23assuming that everything involved with this process is "data analytics". In 23assuming that everything involved with this process is "data analytics". In
24fact, data analytics are only a small part of the process. 24fact, data analytics are only a small part of the process.
25 25
26See **Figure 1** for a more accurate representation of where data analysis 26See **Figure 1** for a more accurate representation of where data analysis sits
27sits within the full process. This means that data analysis does not include 27within the full process. This means that data analysis does not include querying
28querying or extracting data, selecting samples, or performing audit tests. These 28or extracting data, selecting samples, or performing audit tests. These steps
29steps can be necessary for an audit (and may even be performed by the same 29can be necessary for an audit (and may even be performed by the same
30associates), but they are not data analytics. 30associates), but they are not data analytics.
31 31
32![The Intelligence 32![The Intelligence
@@ -45,7 +45,7 @@ companies to perform their roles).
45> a systematic, disciplined approach to evaluate and improve the effectiveness 45> a systematic, disciplined approach to evaluate and improve the effectiveness
46> of risk management, control and governance processes. 46> of risk management, control and governance processes.
47> 47>
48> - The IIA's Definition of Internal Audit 48> - The IIA's Definition of Internal Audit
49 49
50Part of the blame for the slow adoption of data analysis can be attributed to 50Part of the blame for the slow adoption of data analysis can be attributed to
51the fact that internal auditing is strongly based on tradition and following the 51the fact that internal auditing is strongly based on tradition and following the
@@ -73,15 +73,15 @@ look at **Figure 2** for a quick overview of the model.
73The DELTA model sets a few guidelines for areas wanting to implement data 73The DELTA model sets a few guidelines for areas wanting to implement data
74analytics so that the results can be as comprehensive as possible: 74analytics so that the results can be as comprehensive as possible:
75 75
76- **Data**: Must be clean, accessible, and (usually) unique. 76- **Data**: Must be clean, accessible, and (usually) unique.
77- **Enterprise-Wide Focus**: Key data systems and analytical resources must be 77- **Enterprise-Wide Focus**: Key data systems and analytical resources must be
78 available for use (by the Internal Audit Function). 78 available for use (by the Internal Audit Function).
79- **Leaders**: Must promote a data analytics approach and show the value of 79- **Leaders**: Must promote a data analytics approach and show the value of
80 analytical results. 80 analytical results.
81- **Targets**: Must be set for key areas and risks that the analytics can be 81- **Targets**: Must be set for key areas and risks that the analytics can be
82 compared against (KPIs). 82 compared against (KPIs).
83- **Analysts**: There must be auditors willing and able to perform data 83- **Analysts**: There must be auditors willing and able to perform data
84 analytics or else the system cannot be sustained. 84 analytics or else the system cannot be sustained.
85 85
86![The Delta 86![The Delta
87Model](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/delta-min.png) 87Model](https://img.cleberg.net/blog/20190909-data-analysis-in-auditing/delta-min.png)
@@ -110,12 +110,11 @@ some applicable standards, such as IPPF Standard 1300.
110Additionally, IPPF Standard 2060 discusses reporting: 110Additionally, IPPF Standard 2060 discusses reporting:
111 111
112> The chief audit executive must report periodically to senior management and 112> The chief audit executive must report periodically to senior management and
113> the board on the internal audit activity's purpose, authority, 113> the board on the internal audit activity's purpose, authority, responsibility,
114> responsibility, and performance relative to its plan and on its conformance 114> and performance relative to its plan and on its conformance with the Code of
115> with the Code of Ethics and the Standards. Reporting must also include 115> Ethics and the Standards. Reporting must also include significant risk and
116> significant risk and control issues, including fraud risks, governance issues, 116> control issues, including fraud risks, governance issues, and other matters
117> and other matters that require the attention of senior management and/or the 117> that require the attention of senior management and/or the board.
118> board.
119> 118>
120> - IPPF Standard 2060 119> - IPPF Standard 2060
121 120
@@ -163,12 +162,12 @@ where the auditor must write the scripts manually. Python and the R-language are
163solely scripting languages. 162solely scripting languages.
164 163
165The general trend in the data analytics environment is that if the tool allows 164The general trend in the data analytics environment is that if the tool allows
166you to do everything by clicking buttons or dragging elements, you won't be 165you to do everything by clicking buttons or dragging elements, you won't be able
167able to fully utilize the analytics you need. The most robust solutions are 166to fully utilize the analytics you need. The most robust solutions are created
168created by those who understand how to write the scripts manually. It should be 167by those who understand how to write the scripts manually. It should be noted
169noted that as the utility of a tool increases, it usually means that the 168that as the utility of a tool increases, it usually means that the learning
170learning curve for that tool will also be higher. It will take auditors longer 169curve for that tool will also be higher. It will take auditors longer to learn
171to learn how to utilize Python, R, or ACL versus learning how to utilize Excel. 170how to utilize Python, R, or ACL versus learning how to utilize Excel.
172 171
173# Visualization 172# Visualization
174 173
@@ -192,13 +191,13 @@ Lastly, let's take a look at an example of data visualization. This example
192comes from a [blog post written by Kushal 191comes from a [blog post written by Kushal
193Chakrabarti](https://talent.works/2018/03/28/the-science-of-the-job-search-part-iii-61-of-entry-level-jobs-require-3-years-of-experience/) 192Chakrabarti](https://talent.works/2018/03/28/the-science-of-the-job-search-part-iii-61-of-entry-level-jobs-require-3-years-of-experience/)
194in 2018 about the percent of entry-level US jobs that require experience. 193in 2018 about the percent of entry-level US jobs that require experience.
195**Figure 3** shows us an easy-to-digest picture of the data. We can quickly 194**Figure 3** shows us an easy-to-digest picture of the data. We can quickly tell
196tell that only about 12.5% of entry-level jobs don't require experience. 195that only about 12.5% of entry-level jobs don't require experience.
197 196
198This is the kind of result that easily describes the data for you. However, make 197This is the kind of result that easily describes the data for you. However, make
199sure to include an explanation of what the results mean. Don't let the reader 198sure to include an explanation of what the results mean. Don't let the reader
200assume what the data means, especially if it relates to a complex subject. *Tell 199assume what the data means, especially if it relates to a complex subject. _Tell
201a story* about the data and why the results matter. For example, **Figure 4** 200a story_ about the data and why the results matter. For example, **Figure 4**
202shows a part of the explanation the author gives to illustrate his point. 201shows a part of the explanation the author gives to illustrate his point.
203 202
204![Entry-Level 203![Entry-Level
content/blog/2019-12-03-the-ansoff-matrix.md +6 −6
@@ -10,8 +10,8 @@ draft = false
10As the world of business evolves, managers must approach business planning and 10As the world of business evolves, managers must approach business planning and
11strategy with a contemporary mindset. According to Dess, McNamara, Eisner, and 11strategy with a contemporary mindset. According to Dess, McNamara, Eisner, and
12Lee, managers must be willing to adapt to the modern business environment by 12Lee, managers must be willing to adapt to the modern business environment by
13going beyond "'incremental management', whereby they view their job as making 13going beyond "'incremental management', whereby they view their job as making a
14a series of small, minor changes to improve the efficiency of the firm's 14series of small, minor changes to improve the efficiency of the firm's
15operations"(2019). 15operations"(2019).
16 16
17One reason that strategic management is crucial is because most businesses that 17One reason that strategic management is crucial is because most businesses that
@@ -34,8 +34,8 @@ companies to use in this framework: market penetration, market development,
34product development, and diversification (see **Figure 1**). The x-axis of the 34product development, and diversification (see **Figure 1**). The x-axis of the
35matrix focuses on the firm's markets and also determines if the firm is looking 35matrix focuses on the firm's markets and also determines if the firm is looking
36to enter new markets or innovate in its current markets. The y-axis of the 36to enter new markets or innovate in its current markets. The y-axis of the
37matrix focuses on the firm's products and determines if the firm wants to 37matrix focuses on the firm's products and determines if the firm wants to pursue
38pursue strategies around their existing products or explore new products. 38strategies around their existing products or explore new products.
39 39
40![The Ansoff Matrix by JaisonAbeySabu, Own work, CC BY-SA 40![The Ansoff Matrix by JaisonAbeySabu, Own work, CC BY-SA
413.0](https://img.cleberg.net/blog/20191203-the-ansoff-matrix/ansoff_matrix-min.png) 413.0](https://img.cleberg.net/blog/20191203-the-ansoff-matrix/ansoff_matrix-min.png)
@@ -75,8 +75,8 @@ increases in their investor dividends for 57 consecutive years(2019).
75Diversification, the final strategy of the Ansoff Matrix, is more difficult than 75Diversification, the final strategy of the Ansoff Matrix, is more difficult than
76the others since it involves exploring both new markets and new products. 76the others since it involves exploring both new markets and new products.
77Related diversification is a diversification strategy that closely relates to 77Related diversification is a diversification strategy that closely relates to
78the firm's core business. Coca-Cola's best example of related diversification 78the firm's core business. Coca-Cola's best example of related diversification is
79is its acquisition of Glaceau and Vitamin Water, which expanded their drinking 79its acquisition of Glaceau and Vitamin Water, which expanded their drinking
80lines of business(2019). 80lines of business(2019).
81 81
82## Unrelated Diversification 82## Unrelated Diversification
content/blog/2019-12-16-password-security.md +19 −19
@@ -32,10 +32,10 @@ Once you think you have a good idea of all your different authentication
32methods, I recommend using a password manager such as 32methods, I recommend using a password manager such as
33[Bitwarden](https://bitwarden.com/). Using a password manager allows you to 33[Bitwarden](https://bitwarden.com/). Using a password manager allows you to
34automatically save your logins, create randomized passwords, and transfer 34automatically save your logins, create randomized passwords, and transfer
35passwords across devices. However, you'll need to memorize your "vault 35passwords across devices. However, you'll need to memorize your "vault password"
36password" that allows you to open the password manager. It's important to make 36that allows you to open the password manager. It's important to make this
37this something hard to guess since it would allow anyone who has it to access 37something hard to guess since it would allow anyone who has it to access every
38every password you've stored in there. 38password you've stored in there.
39 39
40Personally, I recommend using a 40Personally, I recommend using a
41[passphrase](https://en.wikipedia.org/wiki/Passphrase) instead of a 41[passphrase](https://en.wikipedia.org/wiki/Passphrase) instead of a
@@ -88,25 +88,25 @@ Guidelines and Authentication and Lifecycle Management.
88> it would be impractical for an attacker to guess or otherwise discover the 88> it would be impractical for an attacker to guess or otherwise discover the
89> correct secret value. A memorized secret is something you know. 89> correct secret value. A memorized secret is something you know.
90> 90>
91> - NIST Special Publication 800-63B 91> - NIST Special Publication 800-63B
92 92
93NIST offers a lot of guidance on passwords, but I'm going to highlight just a 93NIST offers a lot of guidance on passwords, but I'm going to highlight just a
94few of the important factors: 94few of the important factors:
95 95
96- Require passwords to be a minimum of 8 characters (6 characters if randomly 96- Require passwords to be a minimum of 8 characters (6 characters if randomly
97 generated and be generated using an approved random bit generator). 97 generated and be generated using an approved random bit generator).
98- Compare potential passwords against a list that contains values known to be 98- Compare potential passwords against a list that contains values known to be
99 commonly-used, expected, or compromised. 99 commonly-used, expected, or compromised.
100- Offer guidance on password strength, such as a strength meter. 100- Offer guidance on password strength, such as a strength meter.
101- Implement a rate-limiting mechanism to limit the number of failed 101- Implement a rate-limiting mechanism to limit the number of failed
102 authentication attempts for each user account. 102 authentication attempts for each user account.
103- Do not require composition rules for passwords and do not require passwords to 103- Do not require composition rules for passwords and do not require passwords
104 be changed periodically (unless compromised). 104 to be changed periodically (unless compromised).
105- Allow pasting of user identification and passwords to facilitate the use of 105- Allow pasting of user identification and passwords to facilitate the use of
106 password managers. 106 password managers.
107- Allow users to view the password as it is being entered. 107- Allow users to view the password as it is being entered.
108- Use secure forms of communication and storage, including salting and hashing 108- Use secure forms of communication and storage, including salting and hashing
109 passwords using a one-way key derivation function. 109 passwords using a one-way key derivation function.
110 110
111NIST offers further guidance on other devices that require specific security 111NIST offers further guidance on other devices that require specific security
112policies, querying for passwords, and more. All the information discussed so far 112policies, querying for passwords, and more. All the information discussed so far
content/blog/2020-01-25-linux-software.md +1 −1
@@ -184,7 +184,7 @@ sudo nano /etc/pacman.conf
184 184
185Now, scroll down and uncomment the `multilib` section. 185Now, scroll down and uncomment the `multilib` section.
186 186
187``` config 187```config
188# Before: 188# Before:
189#[multilib] 189#[multilib]
190#Include = /etc/pacman.d/mirrorlist 190#Include = /etc/pacman.d/mirrorlist
content/blog/2020-01-26-steam-on-ntfs.md +11 −11
@@ -13,11 +13,11 @@ Screenshot](https://img.cleberg.net/blog/20200125-the-best-linux-software/steam.
13If you want to see how to install Steam on Linux, see my other post: [Linux 13If you want to see how to install Steam on Linux, see my other post: [Linux
14Software](../linux-software/). 14Software](../linux-software/).
15 15
16Are you having trouble launching games, even though they've installed 16Are you having trouble launching games, even though they've installed correctly?
17correctly? This may happen if you're storing your games on an NTFS-formatted 17This may happen if you're storing your games on an NTFS-formatted drive. This
18drive. This shouldn't be an issue if you're storing your games on the same 18shouldn't be an issue if you're storing your games on the same drive that Steam
19drive that Steam is on, but some gamers prefer to put Steam on their main drive 19is on, but some gamers prefer to put Steam on their main drive and game files on
20and game files on another SSD or HDD. 20another SSD or HDD.
21 21
22To fix this problem, you'll need to try a few things. First, you'll need to 22To fix this problem, you'll need to try a few things. First, you'll need to
23install the `ntfs-3g` package, which is meant for better interoperability with 23install the `ntfs-3g` package, which is meant for better interoperability with
@@ -44,12 +44,12 @@ mkdir /mnt/steam_library
44``` 44```
45 45
46To automatically mount drives upon system boot, you will need to collect a few 46To automatically mount drives upon system boot, you will need to collect a few
47items. The UUID is the identification number connected to whichever drive 47items. The UUID is the identification number connected to whichever drive you're
48you're using to store Steam games. 48using to store Steam games.
49 49
50Drives are usually labeled similar to `/dev/nvme0n1p1` or `/dev/sda1`, so 50Drives are usually labeled similar to `/dev/nvme0n1p1` or `/dev/sda1`, so you'll
51you'll need to find the line in the output of the command below that correlates 51need to find the line in the output of the command below that correlates to your
52to your drive and copy the UUID over to the `/etc/fstab` file. 52drive and copy the UUID over to the `/etc/fstab` file.
53 53
54```sh 54```sh
55sudo blkid | grep UUID= 55sudo blkid | grep UUID=
@@ -72,7 +72,7 @@ sudo nano /etc/fstab
72Each drive you want to mount on boot should have its own line in the 72Each drive you want to mount on boot should have its own line in the
73`/etc/fstab` file that looks similar to this: 73`/etc/fstab` file that looks similar to this:
74 74
75``` config 75```config
76UUID=B64E53824E5339F7 /mnt/steam_library ntfs-3g uid=1000,gid=1000 0 0 76UUID=B64E53824E5339F7 /mnt/steam_library ntfs-3g uid=1000,gid=1000 0 0
77``` 77```
78 78
content/blog/2020-02-09-cryptography-basics.md +26 −26
@@ -23,7 +23,7 @@ Glossary's definition:
23> transformation is reversible, cryptography also deals with restoring encrypted 23> transformation is reversible, cryptography also deals with restoring encrypted
24> data to an intelligible form. 24> data to an intelligible form.
25> 25>
26> - [Internet Security Glossary (2000)](https://tools.ietf.org/html/rfc2828) 26> - [Internet Security Glossary (2000)](https://tools.ietf.org/html/rfc2828)
27 27
28Cryptography cannot offer protection against the loss of data; it simply offers 28Cryptography cannot offer protection against the loss of data; it simply offers
29encryption methods to protect data at-rest and data in-traffic. At a high-level, 29encryption methods to protect data at-rest and data in-traffic. At a high-level,
@@ -37,15 +37,15 @@ utilizes one or more values called keys to encrypt or decrypt the data.
37To create or evaluate a cryptographic system, you need to know the essential 37To create or evaluate a cryptographic system, you need to know the essential
38pieces to the system: 38pieces to the system:
39 39
40- **Encryption Algorithm (Primitive):** A mathematical process that encrypts 40- **Encryption Algorithm (Primitive):** A mathematical process that encrypts
41 and decrypts data. 41 and decrypts data.
42- **Encryption Key:** A string of bits used within the encryption algorithm as 42- **Encryption Key:** A string of bits used within the encryption algorithm as
43 the secret that allows successful encryption or decryption of data. 43 the secret that allows successful encryption or decryption of data.
44- **Key Length (Size):** The maximum number of bits within the encryption key. 44- **Key Length (Size):** The maximum number of bits within the encryption key.
45 It's important to remember that key size is regulated in many countries. 45 It's important to remember that key size is regulated in many countries.
46- **Message Digest:** A smaller, fixed-size bit string version of the original 46- **Message Digest:** A smaller, fixed-size bit string version of the original
47 message. This is practically infeasible to reverse, which is why it's 47 message. This is practically infeasible to reverse, which is why it's
48 commonly used to verify integrity. 48 commonly used to verify integrity.
49 49
50# Symmetric Systems (Secret Key Cryptography) 50# Symmetric Systems (Secret Key Cryptography)
51 51
@@ -136,9 +136,9 @@ encrypts just the data portion of packets in the transport methods, but it
136encrypts both the data and headers in the tunnel method (introducing an 136encrypts both the data and headers in the tunnel method (introducing an
137additional header for authentication). 137additional header for authentication).
138 138
139**Secure Shell (SSH):** SSH is another network protocol used to protect 139**Secure Shell (SSH):** SSH is another network protocol used to protect network
140network services by authenticating users through a secure channel. This protocol 140services by authenticating users through a secure channel. This protocol is
141is often used for command-line (shell) functions such as remote shell commands, 141often used for command-line (shell) functions such as remote shell commands,
142logins, and file transfers. 142logins, and file transfers.
143 143
144**Kerberos:** Developed by MIT, Kerberos is a computer-network authentication 144**Kerberos:** Developed by MIT, Kerberos is a computer-network authentication
@@ -152,16 +152,16 @@ encryption method for Windows Active Directory (AD).
152If you're someone who needs solutions on how to control risks associated with 152If you're someone who needs solutions on how to control risks associated with
153utilizing a crytograhpic system, start with a few basic controls: 153utilizing a crytograhpic system, start with a few basic controls:
154 154
155- **Policies:** A policy on the use of cryptographic controls for protection 155- **Policies:** A policy on the use of cryptographic controls for protection
156 of information is implemented and is in accordance with organizational 156 of information is implemented and is in accordance with organizational
157 objectives. 157 objectives.
158- **Key management:** A policy on the use, protection and lifetime of 158- **Key management:** A policy on the use, protection and lifetime of
159 cryptographic keys is implemented through the entire application lifecycle. 159 cryptographic keys is implemented through the entire application lifecycle.
160- **Key size:** The organization has researched the optimal key size for their 160- **Key size:** The organization has researched the optimal key size for their
161 purposes, considering national laws, required processing power, and longevity 161 purposes, considering national laws, required processing power, and
162 of the solution. 162 longevity of the solution.
163- **Algorithm selection:** Implemented algorithms are sufficiently appropriate 163- **Algorithm selection:** Implemented algorithms are sufficiently appropriate
164 for the business of the organization, robust, and align with recommended 164 for the business of the organization, robust, and align with recommended
165 guidelines. 165 guidelines.
166- **Protocol configuration:** Protocols have been reviewed and configured 166- **Protocol configuration:** Protocols have been reviewed and configured
167 suitable to the purpose of the business. 167 suitable to the purpose of the business.
content/blog/2020-03-25-session-messenger.md +14 −14
@@ -44,16 +44,16 @@ Since most people are looking for an alternative to a popular chat app, I am
44going to list out the features that Session has so that you are able to 44going to list out the features that Session has so that you are able to
45determine if the app would suit your needs: 45determine if the app would suit your needs:
46 46
47- Multiple device linking (via QR code or ID) 47- Multiple device linking (via QR code or ID)
48- App locking via device screen lock, password, or fingerprint 48- App locking via device screen lock, password, or fingerprint
49- Screenshot blocking 49- Screenshot blocking
50- Incognito keyboard 50- Incognito keyboard
51- Read receipts and typing indicators 51- Read receipts and typing indicators
52- Mobile notification customization 52- Mobile notification customization
53- Old message deletion and conversation limit 53- Old message deletion and conversation limit
54- Backups 54- Backups
55- Recovery phrase 55- Recovery phrase
56- Account deletion, including ID, messages, sessions, and contacts 56- Account deletion, including ID, messages, sessions, and contacts
57 57
58# Downloads 58# Downloads
59 59
@@ -76,8 +76,8 @@ Options](https://img.cleberg.net/blog/20200325-session-private-messenger/session
76 76
77# Creating an Account 77# Creating an Account
78 78
79Once you've installed the app, simply run the app and create your unique 79Once you've installed the app, simply run the app and create your unique Session
80Session ID. It will look something like this: 80ID. It will look something like this:
81`05af1835afdd63c947b47705867501d6373f486aa1ae05b1f2f3fcd24570eba608`. 81`05af1835afdd63c947b47705867501d6373f486aa1ae05b1f2f3fcd24570eba608`.
82 82
83You'll need to set a display name and, optionally, a password. If you set a 83You'll need to set a display name and, optionally, a password. If you set a
@@ -96,8 +96,8 @@ Authentication](https://img.cleberg.net/blog/20200325-session-private-messenger/
96 96
97Once you've created your account and set up your profile details, the next step 97Once you've created your account and set up your profile details, the next step
98is to start messaging other people. To do so, you'll need to share your Session 98is to start messaging other people. To do so, you'll need to share your Session
99ID with other people. From this point, it's fairly straightforward and acts 99ID with other people. From this point, it's fairly straightforward and acts like
100like any other messaging app, so I won't dive into much detail here. 100any other messaging app, so I won't dive into much detail here.
101 101
102## macOS 102## macOS
103 103
content/blog/2020-05-03-homelab.md +11 −11
@@ -32,11 +32,11 @@ Plex and Pi-hole until I grew tired with the slow performance.
32 32
33Here are the specifications for the Pi 4: 33Here are the specifications for the Pi 4:
34 34
35- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz 35- Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz
36- 4GB LPDDR4-3200 SDRAM 36- 4GB LPDDR4-3200 SDRAM
37- Gigabit Ethernet 37- Gigabit Ethernet
38- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode) 38- H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode)
39- 64 GB MicroSD Card 39- 64 GB MicroSD Card
40 40
41## Dell Optiplex 5040 41## Dell Optiplex 5040
42 42
@@ -49,11 +49,11 @@ during quarantine.
49 49
50Here are the specifications for the Dell Optiplex 5040: 50Here are the specifications for the Dell Optiplex 5040:
51 51
52- Intel Core i3 6100 52- Intel Core i3 6100
53- 8GB RAM DDR3 53- 8GB RAM DDR3
54- Intel HD Graphics 54- Intel HD Graphics
55- Gigabit Ethernet 55- Gigabit Ethernet
56- 500GB Hard Drive 56- 500GB Hard Drive
57 57
58While this hardware would be awful for a work computer or a gaming rig, it 58While this hardware would be awful for a work computer or a gaming rig, it
59turned out to be wonderful for my server purposes. The only limitation I have 59turned out to be wonderful for my server purposes. The only limitation I have
@@ -118,7 +118,7 @@ operating system.
118 118
119## Docker 119## Docker
120 120
121I am *very* new to Docker, but I have had a lot of fun playing with it so far. 121I am _very_ new to Docker, but I have had a lot of fun playing with it so far.
122Docker is used to create containers that can hold all the contents of a system 122Docker is used to create containers that can hold all the contents of a system
123without interfering with other software on the same system. So far, I have 123without interfering with other software on the same system. So far, I have
124successfully installed pi-hole, GitLab, Gogs, and Nextcloud in containers. 124successfully installed pi-hole, GitLab, Gogs, and Nextcloud in containers.
content/blog/2020-05-19-customizing-ubuntu.md +7 −8
@@ -7,7 +7,7 @@ draft = false
7 7
8# More Information 8# More Information
9 9
10For inspiration on designing your *nix computer, check out the 10For inspiration on designing your \*nix computer, check out the
11[r/unixporn](https://libredd.it/r/unixporn) subreddit! 11[r/unixporn](https://libredd.it/r/unixporn) subreddit!
12 12
13# Customizing Ubuntu 13# Customizing Ubuntu
@@ -36,10 +36,9 @@ following command:
36sudo apt install gnome-tweaks 36sudo apt install gnome-tweaks
37``` 37```
38 38
39After you've finished installing the tool, simply launch the Tweaks 39After you've finished installing the tool, simply launch the Tweaks application,
40application, and you'll be able to access the various customization options 40and you'll be able to access the various customization options available by
41available by default on Ubuntu. You might even like some of the pre-installed 41default on Ubuntu. You might even like some of the pre-installed options.
42options.
43 42
44## GNOME Application Themes 43## GNOME Application Themes
45 44
@@ -66,8 +65,8 @@ Steps to import themes into Tweaks:
664. Close tweaks if it is open. Re-open Tweaks and your new theme will be 654. Close tweaks if it is open. Re-open Tweaks and your new theme will be
67 available in the Applications dropdown in the Appearance section of Tweaks. 66 available in the Applications dropdown in the Appearance section of Tweaks.
68 67
69If the theme is not showing up after you've moved it into the themes folder, 68If the theme is not showing up after you've moved it into the themes folder, you
70you may have uncompressed the folder into a sub-folder. You can check this by 69may have uncompressed the folder into a sub-folder. You can check this by
71entering the theme folder and listing the contents: 70entering the theme folder and listing the contents:
72 71
73```sh 72```sh
@@ -129,7 +128,7 @@ folders to the `/usr/share/fonts/` directory instead.
129If you spend a lot of time typing commands, you know how important the style and 128If you spend a lot of time typing commands, you know how important the style and
130functionality of the terminal is. After spending a lot of time using the default 129functionality of the terminal is. After spending a lot of time using the default
131GNOME terminal with [unix 130GNOME terminal with [unix
132shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), I decided to try some 131shell](<https://en.wikipedia.org/wiki/Bash_(Unix_shell)>), I decided to try some
133different options. I ended up choosing 132different options. I ended up choosing
134[Terminator](https://terminator-gtk3.readthedocs.io/en/latest/) with 133[Terminator](https://terminator-gtk3.readthedocs.io/en/latest/) with
135[zsh](https://en.wikipedia.org/wiki/Z_shell). 134[zsh](https://en.wikipedia.org/wiki/Z_shell).
content/blog/2020-07-20-video-game-sales.md +21 −21
@@ -14,23 +14,23 @@ scrape of vgchartz.com.
14 14
15Fields include: 15Fields include:
16 16
17- Rank: Ranking of overall sales 17- Rank: Ranking of overall sales
18- Name: The game name 18- Name: The game name
19- Platform: Platform of the game release (i.e. PC,PS4, etc.) 19- Platform: Platform of the game release (i.e. PC,PS4, etc.)
20- Year: Year of the game's release 20- Year: Year of the game's release
21- Genre: Genre of the game 21- Genre: Genre of the game
22- Publisher: Publisher of the game 22- Publisher: Publisher of the game
23- NA~Sales~: Sales in North America (in millions) 23- NA~Sales~: Sales in North America (in millions)
24- EU~Sales~: Sales in Europe (in millions) 24- EU~Sales~: Sales in Europe (in millions)
25- JP~Sales~: Sales in Japan (in millions) 25- JP~Sales~: Sales in Japan (in millions)
26- Other~Sales~: Sales in the rest of the world (in millions) 26- Other~Sales~: Sales in the rest of the world (in millions)
27- Global~Sales~: Total worldwide sales. 27- Global~Sales~: Total worldwide sales.
28 28
29There are 16,598 records. 2 records were dropped due to incomplete information. 29There are 16,598 records. 2 records were dropped due to incomplete information.
30 30
31# Import the Data 31# Import the Data
32 32
33``` python 33```python
34# Import the Python libraries we will be using 34# Import the Python libraries we will be using
35import pandas as pd 35import pandas as pd
36import numpy as np 36import numpy as np
@@ -48,7 +48,7 @@ Results](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales
48 48
49# Explore the Data 49# Explore the Data
50 50
51``` python 51```python
52# With the description function, we can see the basic stats. For example, we can 52# With the description function, we can see the basic stats. For example, we can
53# also see that the 'Year' column has some incomplete values. 53# also see that the 'Year' column has some incomplete values.
54df.describe() 54df.describe()
@@ -56,7 +56,7 @@ df.describe()
56 56
57![df.describe()](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/02_describe-min.png) 57![df.describe()](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/02_describe-min.png)
58 58
59``` python 59```python
60# This function shows the rows and columns of NaN values. For example, df[179,3] = nan 60# This function shows the rows and columns of NaN values. For example, df[179,3] = nan
61np.where(pd.isnull(df)) 61np.where(pd.isnull(df))
62 62
@@ -66,7 +66,7 @@ np.where(pd.isnull(df))
66 66
67# Visualize the Data 67# Visualize the Data
68 68
69``` python 69```python
70# This function plots the global sales by platform 70# This function plots the global sales by platform
71sns.catplot(x='Platform', y='Global_Sales', data=df, jitter=False).set_xticklabels(rotation=90) 71sns.catplot(x='Platform', y='Global_Sales', data=df, jitter=False).set_xticklabels(rotation=90)
72``` 72```
@@ -74,7 +74,7 @@ sns.catplot(x='Platform', y='Global_Sales', data=df, jitter=False).set_xticklabe
74![Plot of Global Sales by 74![Plot of Global Sales by
75Platform](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/03_plot-min.png) 75Platform](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/03_plot-min.png)
76 76
77``` python 77```python
78# This function plots the global sales by genre 78# This function plots the global sales by genre
79sns.catplot(x='Genre', y='Global_Sales', data=df, jitter=False).set_xticklabels(rotation=45) 79sns.catplot(x='Genre', y='Global_Sales', data=df, jitter=False).set_xticklabels(rotation=45)
80``` 80```
@@ -82,7 +82,7 @@ sns.catplot(x='Genre', y='Global_Sales', data=df, jitter=False).set_xticklabels(
82![Plot of Global Sales by 82![Plot of Global Sales by
83Genre](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/04_plot-min.png) 83Genre](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/04_plot-min.png)
84 84
85``` python 85```python
86# This function plots the global sales by year 86# This function plots the global sales by year
87sns.lmplot(x='Year', y='Global_Sales', data=df).set_xticklabels(rotation=45) 87sns.lmplot(x='Year', y='Global_Sales', data=df).set_xticklabels(rotation=45)
88``` 88```
@@ -90,7 +90,7 @@ sns.lmplot(x='Year', y='Global_Sales', data=df).set_xticklabels(rotation=45)
90![Plot of Global Sales by 90![Plot of Global Sales by
91Year](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/05_plot-min.png) 91Year](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/05_plot-min.png)
92 92
93``` python 93```python
94# This function plots four different lines to show sales from different regions. 94# This function plots four different lines to show sales from different regions.
95# The global sales plot line is commented-out, but can be included for comparison 95# The global sales plot line is commented-out, but can be included for comparison
96df2 = df.groupby('Year').sum() 96df2 = df.groupby('Year').sum()
@@ -121,7 +121,7 @@ Year](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/06
121 121
122## Investigate Outliers 122## Investigate Outliers
123 123
124``` python 124```python
125# Find the game with the highest sales in North America 125# Find the game with the highest sales in North America
126df.loc[df['NA_Sales'].idxmax()] 126df.loc[df['NA_Sales'].idxmax()]
127 127
@@ -146,7 +146,7 @@ df3.describe()
146![Descriptive Statistics of 2006 146![Descriptive Statistics of 2006
147Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/07_2006_stats-min.png) 147Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/07_2006_stats-min.png)
148 148
149``` python 149```python
150# Plot the results of the previous dataframe (games from 2006) - we can see the year's results were largely carried by Wii Sports 150# Plot the results of the previous dataframe (games from 2006) - we can see the year's results were largely carried by Wii Sports
151sns.catplot(x="Genre", y="Global_Sales", data=df3, jitter=False).set_xticklabels(rotation=45) 151sns.catplot(x="Genre", y="Global_Sales", data=df3, jitter=False).set_xticklabels(rotation=45)
152``` 152```
@@ -154,7 +154,7 @@ sns.catplot(x="Genre", y="Global_Sales", data=df3, jitter=False).set_xticklabels
154![Plot of 2006 154![Plot of 2006
155Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/08_plot-min.png) 155Sales](https://img.cleberg.net/blog/20200720-data-exploration-video-game-sales/08_plot-min.png)
156 156
157``` python 157```python
158# We can see 4 outliers in the graph above, so let's get the top 5 games from that dataframe 158# We can see 4 outliers in the graph above, so let's get the top 5 games from that dataframe
159# The results below show that Nintendo had all top 5 games (3 on the Wii and 2 on the DS) 159# The results below show that Nintendo had all top 5 games (3 on the Wii and 2 on the DS)
160df3.sort_values(by=['Global_Sales'], ascending=False).head(5) 160df3.sort_values(by=['Global_Sales'], ascending=False).head(5)
content/blog/2020-07-26-business-analysis.md +17 −17
@@ -13,10 +13,10 @@ project was obtained using Foursquare's developer API.
13 13
14Fields include: 14Fields include:
15 15
16- Venue Name 16- Venue Name
17- Venue Category 17- Venue Category
18- Venue Latitude 18- Venue Latitude
19- Venue Longitude 19- Venue Longitude
20 20
21There are 232 records found using the center of Lincoln as the area of interest 21There are 232 records found using the center of Lincoln as the area of interest
22with a radius of 10,000. 22with a radius of 10,000.
@@ -26,7 +26,7 @@ with a radius of 10,000.
26The first step is the simplest: import the applicable libraries. We will be 26The first step is the simplest: import the applicable libraries. We will be
27using the libraries below for this project. 27using the libraries below for this project.
28 28
29``` python 29```python
30# Import the Python libraries we will be using 30# Import the Python libraries we will be using
31import pandas as pd 31import pandas as pd
32import requests 32import requests
@@ -42,7 +42,7 @@ are using in this project comes directly from the Foursquare API. The first step
42is to get the latitude and longitude of the city being studied (Lincoln, NE) and 42is to get the latitude and longitude of the city being studied (Lincoln, NE) and
43setting up the folium map. 43setting up the folium map.
44 44
45``` python 45```python
46# Define the latitude and longitude, then map the results 46# Define the latitude and longitude, then map the results
47latitude = 40.806862 47latitude = 40.806862
48longitude = -96.681679 48longitude = -96.681679
@@ -60,7 +60,7 @@ we use our first API call below to determine the total results that Foursquare
60has found. Since the total results are 232, we perform the API fetching process 60has found. Since the total results are 232, we perform the API fetching process
61three times (100 + 100 + 32 = 232). 61three times (100 + 100 + 32 = 232).
62 62
63``` python 63```python
64# Foursquare API credentials 64# Foursquare API credentials
65CLIENT_ID = 'your-client-id' 65CLIENT_ID = 'your-client-id'
66CLIENT_SECRET = 'your-client-secret' 66CLIENT_SECRET = 'your-client-secret'
@@ -129,7 +129,7 @@ the categories and name from each business's entry in the Foursquare data
129automatically. Once all the data has been labeled and combined, the results are 129automatically. Once all the data has been labeled and combined, the results are
130stored in the `nearby_venues` dataframe. 130stored in the `nearby_venues` dataframe.
131 131
132``` python 132```python
133# This function will extract the category of the venue from the API dictionary 133# This function will extract the category of the venue from the API dictionary
134def get_category_type(row): 134def get_category_type(row):
135 try: 135 try:
@@ -203,7 +203,7 @@ We now have a complete, clean data set. The next step is to visualize this data
203onto the map we created earlier. We will be using folium's `CircleMarker()` 203onto the map we created earlier. We will be using folium's `CircleMarker()`
204function to do this. 204function to do this.
205 205
206``` python 206```python
207# add markers to map 207# add markers to map
208for lat, lng, name, categories in zip(nearby_venues['lat'], nearby_venues['lng'], nearby_venues['name'], nearby_venues['categories']): 208for lat, lng, name, categories in zip(nearby_venues['lat'], nearby_venues['lng'], nearby_venues['name'], nearby_venues['categories']):
209 label = '{} ({})'.format(name, categories) 209 label = '{} ({})'.format(name, categories)
@@ -224,18 +224,18 @@ map_LNK
224\![Initial data 224\![Initial data
225map](https://img.cleberg.net/blog/20200726-ibm-data-science/03_data_map-min.png) 225map](https://img.cleberg.net/blog/20200726-ibm-data-science/03_data_map-min.png)
226 226
227# Clustering: *k-means* 227# Clustering: _k-means_
228 228
229To cluster the data, we will be using the *k-means* algorithm. This algorithm is 229To cluster the data, we will be using the _k-means_ algorithm. This algorithm is
230iterative and will automatically make sure that data points in each cluster are 230iterative and will automatically make sure that data points in each cluster are
231as close as possible to each other, while being as far as possible away from 231as close as possible to each other, while being as far as possible away from
232other clusters. 232other clusters.
233 233
234However, we first have to figure out how many clusters to use (defined as the 234However, we first have to figure out how many clusters to use (defined as the
235variable *'k'*). To do so, we will use the next two functions to calculate the 235variable _'k'_). To do so, we will use the next two functions to calculate the
236sum of squares within clusters and then return the optimal number of clusters. 236sum of squares within clusters and then return the optimal number of clusters.
237 237
238``` python 238```python
239# This function will return the sum of squares found in the data 239# This function will return the sum of squares found in the data
240def calculate_wcss(data): 240def calculate_wcss(data):
241 wcss = [] 241 wcss = []
@@ -275,7 +275,7 @@ Now that we have found that our optimal number of clusters is six, we need to
275perform k-means clustering. When this clustering occurs, each business is 275perform k-means clustering. When this clustering occurs, each business is
276assigned a cluster number from 0 to 5 in the dataframe. 276assigned a cluster number from 0 to 5 in the dataframe.
277 277
278``` python 278```python
279# set number of clusters equal to the optimal number 279# set number of clusters equal to the optimal number
280kclusters = n 280kclusters = n
281 281
@@ -289,7 +289,7 @@ nearby_venues.insert(0, 'Cluster Labels', kmeans.labels_)
289Success! We now have a dataframe with clean business data, along with a cluster 289Success! We now have a dataframe with clean business data, along with a cluster
290number for each business. Now let's map the data using six different colors. 290number for each business. Now let's map the data using six different colors.
291 291
292``` python 292```python
293# create map with clusters 293# create map with clusters
294map_clusters = folium.Map(location=[latitude, longitude], zoom_start=12) 294map_clusters = folium.Map(location=[latitude, longitude], zoom_start=12)
295colors = ['#0F9D58', '#DB4437', '#4285F4', '#800080', '#ce12c0', '#171717'] 295colors = ['#0F9D58', '#DB4437', '#4285F4', '#800080', '#ce12c0', '#171717']
@@ -321,7 +321,7 @@ which clusters are more popular for businesses and which are less popular. The
321results below show us that clusters 0 through 3 are popular, while clusters 4 321results below show us that clusters 0 through 3 are popular, while clusters 4
322and 5 are not very popular at all. 322and 5 are not very popular at all.
323 323
324``` python 324```python
325# Show how many venues are in each cluster 325# Show how many venues are in each cluster
326color_names = ['Dark Green', 'Red', 'Blue', 'Purple', 'Pink', 'Black'] 326color_names = ['Dark Green', 'Red', 'Blue', 'Purple', 'Pink', 'Black']
327for x in range(0,6): 327for x in range(0,6):
@@ -337,7 +337,7 @@ Our last piece of analysis is to summarize the categories of businesses within
337each cluster. With these results, we can clearly see that restaurants, coffee 337each cluster. With these results, we can clearly see that restaurants, coffee
338shops, and grocery stores are the most popular. 338shops, and grocery stores are the most popular.
339 339
340``` python 340```python
341# Calculate how many venues there are in each category 341# Calculate how many venues there are in each category
342# Sort from largest to smallest 342# Sort from largest to smallest
343temp_df = nearby_venues.drop(columns=['name', 'lat', 'lng']) 343temp_df = nearby_venues.drop(columns=['name', 'lat', 'lng'])
content/blog/2020-08-22-redirect-github-pages.md +1 −1
@@ -25,7 +25,7 @@ DNS configuration.
25 25
26Add these 5 entries to the very top of your DNS configuration: 26Add these 5 entries to the very top of your DNS configuration:
27 27
28``` txt 28```txt
29@ A 185.199.108.153 29@ A 185.199.108.153
30@ A 185.199.109.153 30@ A 185.199.109.153
31@ A 185.199.110.153 31@ A 185.199.110.153
content/blog/2020-08-29-php-auth-flow.md +13 −13
@@ -17,7 +17,7 @@ copying and pasting the code from their library's documentation. For example,
17here's the code I use to authenticate users with the Tumblr OAuth API for my 17here's the code I use to authenticate users with the Tumblr OAuth API for my
18Tumblr client, Vox Populi: 18Tumblr client, Vox Populi:
19 19
20``` php 20```php
21// Start the session 21// Start the session
22session_start(); 22session_start();
23 23
@@ -52,13 +52,13 @@ MySQL database and PHP.
52The beginning to any type of user authentication is to create a user account. 52The beginning to any type of user authentication is to create a user account.
53This process can take many formats, but the simplest is to accept user input 53This process can take many formats, but the simplest is to accept user input
54from a form (e.g., username and password) and send it over to your database. For 54from a form (e.g., username and password) and send it over to your database. For
55example, here's a snippet that shows how to get username and password 55example, here's a snippet that shows how to get username and password parameters
56parameters that would come when a user submits a form to your PHP script. 56that would come when a user submits a form to your PHP script.
57 57
58**Note**: Ensure that your password column is large enough to hold the hashed 58**Note**: Ensure that your password column is large enough to hold the hashed
59value (at least 60 characters or longer). 59value (at least 60 characters or longer).
60 60
61``` php 61```php
62// Get the values from the URL 62// Get the values from the URL
63$username = $_POST['username']; 63$username = $_POST['username'];
64$raw_password = $_POST['password']; 64$raw_password = $_POST['password'];
@@ -99,7 +99,7 @@ To be able to verify that a returning user has a valid username and password in
99your database is as simple as having users fill out a form and comparing their 99your database is as simple as having users fill out a form and comparing their
100inputs to your database. 100inputs to your database.
101 101
102``` php 102```php
103// Query the database for username and password 103// Query the database for username and password
104// ... 104// ...
105 105
@@ -115,24 +115,24 @@ if(password_verify($password_input, $hashed_password)) {
115# Storing Authentication State 115# Storing Authentication State
116 116
117Once you've created the user's account, now you're ready to initialize the 117Once you've created the user's account, now you're ready to initialize the
118user's session. **You will need to do this on every page you load while the 118user's session. **You will need to do this on every page you load while the user
119user is logged in.** To do so, simply enter the following code snippet: 119is logged in.** To do so, simply enter the following code snippet:
120 120
121``` php 121```php
122session_start(); 122session_start();
123``` 123```
124 124
125Once you've initialized the session, the next step is to store the session in a 125Once you've initialized the session, the next step is to store the session in a
126cookie so that you can access it later. 126cookie so that you can access it later.
127 127
128``` php 128```php
129setcookie(session_name()); 129setcookie(session_name());
130``` 130```
131 131
132Now that the session name has been stored, you'll be able to check if there's 132Now that the session name has been stored, you'll be able to check if there's an
133an active session whenever you load a page. 133active session whenever you load a page.
134 134
135``` php 135```php
136if(isset(session_name())) { 136if(isset(session_name())) {
137 // The session is active 137 // The session is active
138} 138}
@@ -144,7 +144,7 @@ The next logical step is to give your users the option to log out once they are
144done using your application. This can be tricky in PHP since a few of the 144done using your application. This can be tricky in PHP since a few of the
145standard ways do not always work. 145standard ways do not always work.
146 146
147``` php 147```php
148// Initialize the session. 148// Initialize the session.
149// If you are using session_name("something"), don't forget it now! 149// If you are using session_name("something"), don't forget it now!
150session_start(); 150session_start();
content/blog/2020-09-01-visual-recognition.md +10 −10
@@ -7,13 +7,13 @@ draft = false
7 7
8# What is IBM Watson? 8# What is IBM Watson?
9 9
10If you've never heard of [Watson](https://www.ibm.com/watson), this service is 10If you've never heard of [Watson](https://www.ibm.com/watson), this service is a
11a suite of enterprise-ready AI services, applications, and tooling provided by 11suite of enterprise-ready AI services, applications, and tooling provided by
12IBM. Watson contains quite a few useful tools for data scientists and students, 12IBM. Watson contains quite a few useful tools for data scientists and students,
13including the subject of this post today: visual recognition. 13including the subject of this post today: visual recognition.
14 14
15If you'd like to view the official documentation for the Visual Recognition 15If you'd like to view the official documentation for the Visual Recognition API,
16API, visit the [API 16visit the [API
17Docs](https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?code=python). 17Docs](https://cloud.ibm.com/apidocs/visual-recognition/visual-recognition-v3?code=python).
18 18
19# Prerequisites 19# Prerequisites
@@ -52,7 +52,7 @@ pip install --upgrade --user "ibm-watson>=4.5.0"
52Next, we need to specify the API key, version, and URL given to us when we 52Next, we need to specify the API key, version, and URL given to us when we
53created the Watson Visual Recognition service. 53created the Watson Visual Recognition service.
54 54
55``` python 55```python
56apikey = "<your-apikey>" 56apikey = "<your-apikey>"
57version = "2018-03-19" 57version = "2018-03-19"
58url = "<your-url>" 58url = "<your-url>"
@@ -60,7 +60,7 @@ url = "<your-url>"
60 60
61Now, let's import the necessary libraries and authenticate our service. 61Now, let's import the necessary libraries and authenticate our service.
62 62
63``` python 63```python
64import json 64import json
65from ibm_watson import VisualRecognitionV3 65from ibm_watson import VisualRecognitionV3
66from ibm_cloud_sdk_core.authenticators import IAMAuthenticator 66from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
@@ -77,14 +77,14 @@ visual_recognition.set_service_url(url)
77**[Optional]** If you'd like to tell the API not to use any data to improve 77**[Optional]** If you'd like to tell the API not to use any data to improve
78their products, set the following header. 78their products, set the following header.
79 79
80``` python 80```python
81visual_recognition.set_default_headers({'x-watson-learning-opt-out': "true"}) 81visual_recognition.set_default_headers({'x-watson-learning-opt-out': "true"})
82``` 82```
83 83
84Now we have our API all set and ready to go. For this example, I'm going to 84Now we have our API all set and ready to go. For this example, I'm going to
85include a `dict` of photos to load as we test out the API. 85include a `dict` of photos to load as we test out the API.
86 86
87``` python 87```python
88data = [ 88data = [
89 { 89 {
90 "title": "Grizzly Bear", 90 "title": "Grizzly Bear",
@@ -122,7 +122,7 @@ each section.
122In the case of an API error, the codes and explanations are output to the 122In the case of an API error, the codes and explanations are output to the
123console. 123console.
124 124
125``` python 125```python
126from ibm_watson import ApiException 126from ibm_watson import ApiException
127 127
128for x in range(len(data)): 128for x in range(len(data)):
@@ -164,7 +164,7 @@ or greater, you would simply adjust the `threshold` in the
164When your program runs, it should show the output below for each photo you 164When your program runs, it should show the output below for each photo you
165provide. 165provide.
166 166
167``` txt 167```txt
168---------------------------------------------------------------- 168----------------------------------------------------------------
169Image Title: Grizzly Bear 169Image Title: Grizzly Bear
170Image URL: https://example.com/photos/image1.jpg 170Image URL: https://example.com/photos/image1.jpg
content/blog/2020-09-22-internal-audit.md +10 −9
@@ -12,8 +12,8 @@ Overview](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-
12 12
13One of the many reasons that Internal Audit needs such thorough explaining to 13One of the many reasons that Internal Audit needs such thorough explaining to
14non-auditors is that Internal Audit can serve many purposes, depending on the 14non-auditors is that Internal Audit can serve many purposes, depending on the
15organization's size and needs. However, the Institute of Internal Auditors 15organization's size and needs. However, the Institute of Internal Auditors (IIA)
16(IIA) defines Internal Auditing as: 16defines Internal Auditing as:
17 17
18> Internal auditing is an independent, objective assurance and consulting 18> Internal auditing is an independent, objective assurance and consulting
19> activity designed to add value and improve an organization's operations. It 19> activity designed to add value and improve an organization's operations. It
@@ -54,9 +54,10 @@ function, process, system, or other subject matters. The internal auditor
54determines the nature and scope of an assurance engagement. Generally, three 54determines the nature and scope of an assurance engagement. Generally, three
55parties are participants in assurance services: (1) the person or group directly 55parties are participants in assurance services: (1) the person or group directly
56involved with the entity, operation, function, process, system, or other subject 56involved with the entity, operation, function, process, system, or other subject
57- (the process owner), (2) the person or group making the assessment - (the 57
58internal auditor), and (3) the person or group using the assessment - (the 58- (the process owner), (2) the person or group making the assessment - (the
59user). 59 internal auditor), and (3) the person or group using the assessment - (the
60 user).
60 61
61## Consulting 62## Consulting
62 63
@@ -121,10 +122,10 @@ model.
121Looking at this model from an auditing perspective shows us that auditors will 122Looking at this model from an auditing perspective shows us that auditors will
122need to align, communicate, and collaborate with management, including business 123need to align, communicate, and collaborate with management, including business
123area managers and chief officers, as well as reporting to the governing body. 124area managers and chief officers, as well as reporting to the governing body.
124The governing body will instruct internal audit *functionally* on their goals 125The governing body will instruct internal audit _functionally_ on their goals
125and track their progress periodically. 126and track their progress periodically.
126 127
127However, the internal audit department will report *administratively* to a chief 128However, the internal audit department will report _administratively_ to a chief
128officer in the company for the purposes of collaboration, direction, and 129officer in the company for the purposes of collaboration, direction, and
129assistance with the business. Note that in most situations, the governing body 130assistance with the business. Note that in most situations, the governing body
130is the audit committee on the company's board of directors. 131is the audit committee on the company's board of directors.
@@ -136,8 +137,8 @@ objective function that can provide assurance over the topics they audit.
136 137
137A normal audit will generally follow the same process, regardless of the topic. 138A normal audit will generally follow the same process, regardless of the topic.
138However, certain special projects or abnormal business areas may call for 139However, certain special projects or abnormal business areas may call for
139changes to the audit process. The audit process is not set in stone, it's 140changes to the audit process. The audit process is not set in stone, it's simply
140simply a set of best practices so that audits can be performed consistently. 141a set of best practices so that audits can be performed consistently.
141 142
142![The Internal Audit 143![The Internal Audit
143Process](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-audit-process.jpg) 144Process](https://img.cleberg.net/blog/20200922-what-is-internal-audit/internal-audit-process.jpg)
content/blog/2020-09-25-happiness-map.md +21 −21
@@ -14,14 +14,14 @@ scores, as well as other national scoring measures.
14 14
15Fields include: 15Fields include:
16 16
17- Overall rank 17- Overall rank
18- Country or region 18- Country or region
19- GDP per capita 19- GDP per capita
20- Social support 20- Social support
21- Healthy life expectancy 21- Healthy life expectancy
22- Freedom to make life choices 22- Freedom to make life choices
23- Generosity 23- Generosity
24- Perceptions of corruption 24- Perceptions of corruption
25 25
26There are 156 records. Since there are ~195 countries in the world, we can see 26There are 156 records. Since there are ~195 countries in the world, we can see
27that around 40 countries will be missing from this dataset. 27that around 40 countries will be missing from this dataset.
@@ -31,7 +31,7 @@ that around 40 countries will be missing from this dataset.
31As always, run the `install` command for all packages needed to perform 31As always, run the `install` command for all packages needed to perform
32analysis. 32analysis.
33 33
34``` python 34```python
35!pip install folium geopandas matplotlib numpy pandas 35!pip install folium geopandas matplotlib numpy pandas
36``` 36```
37 37
@@ -42,7 +42,7 @@ We only need a couple packages to create a choropleth map. We will use
42visualizations in Python. We will also use geopandas and pandas to wrangle our 42visualizations in Python. We will also use geopandas and pandas to wrangle our
43data before we put it on a map. 43data before we put it on a map.
44 44
45``` python 45```python
46# Import the necessary Python packages 46# Import the necessary Python packages
47import folium 47import folium
48import geopandas as gpd 48import geopandas as gpd
@@ -58,7 +58,7 @@ GeoPandas will take this data and load it into a dataframe so that we can easily
58match it to the data we're trying to analyze. Let's look at the GeoJSON 58match it to the data we're trying to analyze. Let's look at the GeoJSON
59dataframe: 59dataframe:
60 60
61``` python 61```python
62# Load the GeoJSON data with geopandas 62# Load the GeoJSON data with geopandas
63geo_data = gpd.read_file('https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson') 63geo_data = gpd.read_file('https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson')
64geo_data.head() 64geo_data.head()
@@ -67,11 +67,11 @@ geo_data.head()
67![GeoJSON 67![GeoJSON
68Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/geojson_df.png) 68Dataframe](https://img.cleberg.net/blog/20200925-world-choropleth-map/geojson_df.png)
69 69
70Next, let's load the data from the Kaggle dataset. I've downloaded this file, 70Next, let's load the data from the Kaggle dataset. I've downloaded this file, so
71so update the file path if you have it somewhere else. After loading, let's 71update the file path if you have it somewhere else. After loading, let's take a
72take a look at this dataframe: 72look at this dataframe:
73 73
74``` python 74```python
75# Load the world happiness data with pandas 75# Load the world happiness data with pandas
76happy_data = pd.read_csv(r'~/Downloads/world_happiness_data_2019.csv') 76happy_data = pd.read_csv(r'~/Downloads/world_happiness_data_2019.csv')
77happy_data.head() 77happy_data.head()
@@ -88,7 +88,7 @@ below showed empty countries. I searched both data frames for the missing
88countries to see the naming differences. Any countries that do not have records 88countries to see the naming differences. Any countries that do not have records
89in the `happy_data` df will not show up on the map. 89in the `happy_data` df will not show up on the map.
90 90
91``` python 91```python
92# Rename some countries to match our GeoJSON data 92# Rename some countries to match our GeoJSON data
93 93
94# Rename USA 94# Rename USA
@@ -111,13 +111,13 @@ happy_data.at[democratic_congo_index, 'Country or region'] = 'Democratic Republi
111# Merge the Data 111# Merge the Data
112 112
113Now that we have clean data, we need to merge the GeoJSON data with the 113Now that we have clean data, we need to merge the GeoJSON data with the
114happiness data. Since we've stored them both in dataframes, we just need to 114happiness data. Since we've stored them both in dataframes, we just need to call
115call the `.merge()` function. 115the `.merge()` function.
116 116
117We will also rename a couple columns, just so that they're a little easier to 117We will also rename a couple columns, just so that they're a little easier to
118use when we create the map. 118use when we create the map.
119 119
120``` python 120```python
121# Merge the two previous dataframes into a single geopandas dataframe 121# Merge the two previous dataframes into a single geopandas dataframe
122merged_df = geo_data.merge(happy_data,left_on='ADMIN', right_on='Country or region') 122merged_df = geo_data.merge(happy_data,left_on='ADMIN', right_on='Country or region')
123 123
@@ -136,7 +136,7 @@ simplest way to find the center of the map and create a Folium map object. The
136important part is to remember to reference the merged dataframe for our GeoJSON 136important part is to remember to reference the merged dataframe for our GeoJSON
137data and value data. The columns specify which geo data and value data to use. 137data and value data. The columns specify which geo data and value data to use.
138 138
139``` python 139```python
140# Assign centroids to map 140# Assign centroids to map
141x_map = merged_df.centroid.x.mean() 141x_map = merged_df.centroid.x.mean()
142y_map = merged_df.centroid.y.mean() 142y_map = merged_df.centroid.y.mean()
@@ -173,7 +173,7 @@ Now that we have a map set up, we could stop. However, I want to add a tooltip
173so that I can see more information about each country. The `tooltip_data` code 173so that I can see more information about each country. The `tooltip_data` code
174below will show a popup on hover with all the data fields shown. 174below will show a popup on hover with all the data fields shown.
175 175
176``` python 176```python
177 # Adding labels to map 177 # Adding labels to map
178 style_function = lambda x: {'fillColor': '#ffffff', 178 style_function = lambda x: {'fillColor': '#ffffff',
179 'color':'#000000', 179 'color':'#000000',
content/blog/2020-10-12-mediocrity.md +6 −6
@@ -16,7 +16,7 @@ allowed us to reach a lesser yet still superb solution.
16 16
17Philosophers throughout history have inspected this plight from many viewpoints. 17Philosophers throughout history have inspected this plight from many viewpoints.
18Greek mythology speaks of the [golden 18Greek mythology speaks of the [golden
19mean](https://en.wikipedia.org/wiki/Golden_mean_(philosophy)), which uses the 19mean](<https://en.wikipedia.org/wiki/Golden_mean_(philosophy)>), which uses the
20story of Icarus to illustrate that sometimes "the middle course" is the best 20story of Icarus to illustrate that sometimes "the middle course" is the best
21solution. In this story, Daedalus, a famous artist of his time, built feathered 21solution. In this story, Daedalus, a famous artist of his time, built feathered
22wings for himself and his son so that they might escape the clutches of King 22wings for himself and his son so that they might escape the clutches of King
@@ -40,9 +40,9 @@ considered.
40 40
41Over and over throughout history, we've found that perfection is often 41Over and over throughout history, we've found that perfection is often
42unrealistic and unachievable. However, we push ourselves and our peers to "give 42unrealistic and unachievable. However, we push ourselves and our peers to "give
43100%" or "go the extra mile," while it may be that the better course is to 43100%" or "go the extra mile," while it may be that the better course is to give
44give a valuable level of effort while considering the effects of further effort 44a valuable level of effort while considering the effects of further effort on
45on the outcome. Working harder does not always help us achieve loftier goals. 45the outcome. Working harder does not always help us achieve loftier goals.
46 46
47This has presented itself to me most recently during my time studying at my 47This has presented itself to me most recently during my time studying at my
48university. I was anxious and feeling the stresses of my courses, career, and 48university. I was anxious and feeling the stresses of my courses, career, and
@@ -56,8 +56,8 @@ talking to my father when he said something simple that hit home:
56The thought was extremely straightforward and uncomplicated, yet it was 56The thought was extremely straightforward and uncomplicated, yet it was
57something that I had lost sight of during my stress-filled years at school. Ever 57something that I had lost sight of during my stress-filled years at school. Ever
58since then, I've found myself pausing and remembering that quote every time I 58since then, I've found myself pausing and remembering that quote every time I
59get anxious or stressed. It helps to stop and think "Can I do anything to 59get anxious or stressed. It helps to stop and think "Can I do anything to affect
60affect the outcome, or am I simply worrying over something I can't change?" 60the outcome, or am I simply worrying over something I can't change?"
61 61
62# When Mediocrity Isn't Enough 62# When Mediocrity Isn't Enough
63 63
content/blog/2020-12-27-website-redesign.md +18 −19
@@ -15,17 +15,16 @@ subdomains.
15 15
16One of the parts I've enjoyed the most about web development is the aspect of 16One of the parts I've enjoyed the most about web development is the aspect of
17designing an identity for a web page and working to find exciting ways to 17designing an identity for a web page and working to find exciting ways to
18display the site's content. Inevitably, this means I've changed the designs 18display the site's content. Inevitably, this means I've changed the designs for
19for my websites more times than I could possibly count. Since I don't really 19my websites more times than I could possibly count. Since I don't really host
20host anything on my main webpage that's vital, it allows me the freedom to 20anything on my main webpage that's vital, it allows me the freedom to change
21change things as inspiration strikes. 21things as inspiration strikes.
22 22
23Historically, I've relied on core utilities for spacing, components, and 23Historically, I've relied on core utilities for spacing, components, and layouts
24layouts from [Bootstrap](https://getbootstrap.com) and added custom CSS for 24from [Bootstrap](https://getbootstrap.com) and added custom CSS for fonts,
25fonts, accents, colors, and other items. I also tend to create sites with no 25accents, colors, and other items. I also tend to create sites with no border
26border radius on items, visible borders, and content that takes up the entire 26radius on items, visible borders, and content that takes up the entire screen
27screen (using whitespace inside components instead of whitespace around my 27(using whitespace inside components instead of whitespace around my components).
28components).
29 28
30# The Redesign Process 29# The Redesign Process
31 30
@@ -45,8 +44,8 @@ brutalist web design doesn't have to be minimal, it often is.
45 44
46I suppose, in a way, I did create a brutalist website since my HTML is semantic 45I suppose, in a way, I did create a brutalist website since my HTML is semantic
47and accessible, hyperlinks are colored and underlined, and all native browser 46and accessible, hyperlinks are colored and underlined, and all native browser
48functions like scrolling and the back button work as expected. However, I 47functions like scrolling and the back button work as expected. However, I didn't
49didn't think about brutalism while designing these sites. 48think about brutalism while designing these sites.
50 49
51The new design followed a simple design process. I walked through the screens on 50The new design followed a simple design process. I walked through the screens on
52my blog and asked myself: "Is this element necessary for a user?" This allowed 51my blog and asked myself: "Is this element necessary for a user?" This allowed
@@ -60,10 +59,10 @@ blog post descriptions, and the scroll-to-top button. It also helped to move all
60categories to a single page, rather than have each category on its own page. 59categories to a single page, rather than have each category on its own page.
61 60
62The final big piece to finish the 61The final big piece to finish the
63"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)"-like 62"[KonMari](https://en.wikipedia.org/wiki/Marie_Kondo#KonMari_method)"-like part
64part of my process was to remove Bootstrap CSS in its entirety. However, this 63of my process was to remove Bootstrap CSS in its entirety. However, this meant
65meant pulling out a few very useful classes, such as `.img-fluid` and the 64pulling out a few very useful classes, such as `.img-fluid` and the default font
66default font stacks to keep in my custom CSS. 65stacks to keep in my custom CSS.
67 66
68After removing all the unnecessary pieces, I was finally able to reorganize my 67After removing all the unnecessary pieces, I was finally able to reorganize my
69content and add a very small amount of custom CSS to make everything pretty. 68content and add a very small amount of custom CSS to make everything pretty.
@@ -91,5 +90,5 @@ for all four categories! First contextual paints of the blog homepage are under
91is within a separate CSS file, and the CSS for my main website is simply 90is within a separate CSS file, and the CSS for my main website is simply
92embedded in the HTML file. 91embedded in the HTML file.
93 92
94Now that everything is complete, I can confidently say I'm happy with the 93Now that everything is complete, I can confidently say I'm happy with the result
95result and proud to look at the fastest set of websites I've created so far. 94and proud to look at the fastest set of websites I've created so far.
content/blog/2020-12-28-neon-drive.md +7 −7
@@ -70,19 +70,19 @@ endurance game mode.
70Neon Drive sits nicely within the well-founded cult genre of Outrun. Other games 70Neon Drive sits nicely within the well-founded cult genre of Outrun. Other games
71that I've enjoyed in this same spectrum are: 71that I've enjoyed in this same spectrum are:
72 72
73- [Far Cry 3: Blood 73- [Far Cry 3: Blood
74 Dragon](https://store.steampowered.com/app/233270/Far_Cry_3__Blood_Dragon/) 74 Dragon](https://store.steampowered.com/app/233270/Far_Cry_3__Blood_Dragon/)
75- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/) 75- [Retrowave](https://store.steampowered.com/app/1239690/Retrowave/)
76- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/) 76- [Slipstream](https://store.steampowered.com/app/732810/Slipstream/)
77 77
78Although these games aren't necessarily in the same genre, they do have aspects 78Although these games aren't necessarily in the same genre, they do have aspects
79that place them close enough to interest gamers that enjoyed Neon Drive: 79that place them close enough to interest gamers that enjoyed Neon Drive:
80 80
81- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/) 81- [Black Ice](https://store.steampowered.com/app/311800/Black_Ice/)
82- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/) 82- [Cloudpunk](https://store.steampowered.com/app/746850/Cloudpunk/)
83- [Need for Speed: 83- [Need for Speed:
84 Heat](https://store.steampowered.com/app/1222680/Need_for_Speed_Heat/) 84 Heat](https://store.steampowered.com/app/1222680/Need_for_Speed_Heat/)
85- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/) 85- [VirtuaVerse](https://store.steampowered.com/app/1019310/VirtuaVerse/)
86 86
87Of course, if all you really care about is the arcade aspect of these games, you 87Of course, if all you really care about is the arcade aspect of these games, you
88can check out the [Atari 88can check out the [Atari
content/blog/2020-12-29-zork.md +13 −14
@@ -14,8 +14,8 @@ up and take a ride back to the 1980s with this masterpiece.
14 14
15# Game Description 15# Game Description
16 16
17Zork is an interactive, text-based computer game originally released in 17Zork is an interactive, text-based computer game originally released in 1980.
181980. This series, split into three separate games, introduced a robust and 18This series, split into three separate games, introduced a robust and
19sophisticated text parser to gamers. People were largely used to the simple 19sophisticated text parser to gamers. People were largely used to the simple
20commands used in the popular game [Colossal Cave 20commands used in the popular game [Colossal Cave
21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but Zork 21Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), but Zork
@@ -37,7 +37,7 @@ intended, you should try to play it without using the map.
37 37
38![Zork Map](https://img.cleberg.net/blog/20201229-zork/zork_map.png) 38![Zork Map](https://img.cleberg.net/blog/20201229-zork/zork_map.png)
39 39
40*[Map Source](https://www.filfre.net/2012/01/exploring-zork-part-1/)* 40_[Map Source](https://www.filfre.net/2012/01/exploring-zork-part-1/)_
41 41
42# In-Game Screenshots 42# In-Game Screenshots
43 43
@@ -45,25 +45,24 @@ After playing the game (for the first time ever) for several weeks around 2014,
45I was finally able to beat the game with some online help to find the last 45I was finally able to beat the game with some online help to find the last
46couple items. As I was writing this post, I installed the game again to grab 46couple items. As I was writing this post, I installed the game again to grab
47some screenshots to show off the true glory of this game. As noted in [Jimmy 47some screenshots to show off the true glory of this game. As noted in [Jimmy
48Maher's playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/), 48Maher's playthrough](https://www.filfre.net/2012/01/exploring-zork-part-1/), the
49the original Zork games looked quite a bit different due to the older hardware 49original Zork games looked quite a bit different due to the older hardware of
50of computers like the Apple II and multiple bug fixes that Infocom pushed out 50computers like the Apple II and multiple bug fixes that Infocom pushed out after
51after the game's initial release. My play-through uses the [Zork 51the game's initial release. My play-through uses the [Zork
52Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/) version, 52Anthology](https://store.steampowered.com/app/570580/Zork_Anthology/) version,
53which utilizes DOSBox on Windows. 53which utilizes DOSBox on Windows.
54 54
55The first screenshot here shows the introductory information, which doesn't 55The first screenshot here shows the introductory information, which doesn't
56include instructions of any kind for the player. If you haven't played text 56include instructions of any kind for the player. If you haven't played text
57adventures before, try to use simple commands like "go west," "look around," 57adventures before, try to use simple commands like "go west," "look around," or
58or "hit troll with elvish sword." 58"hit troll with elvish sword."
59 59
60![Zork Screen, pt. 1](https://img.cleberg.net/blog/20201229-zork/zork_01.png) 60![Zork Screen, pt. 1](https://img.cleberg.net/blog/20201229-zork/zork_01.png)
61 61
62In this second screenshot, we see the player has entered the house and found the 62In this second screenshot, we see the player has entered the house and found the
63trophy case in the living room. The lantern and sword in this room allow the 63trophy case in the living room. The lantern and sword in this room allow the
64player to explore dark areas and attack enemies. If you don't use the lantern, 64player to explore dark areas and attack enemies. If you don't use the lantern,
65you won't be able to see anything in dark areas, and you may be eaten by a 65you won't be able to see anything in dark areas, and you may be eaten by a grue.
66grue.
67 66
68![Zork Screen, pt. 2](https://img.cleberg.net/blog/20201229-zork/zork_02.png) 67![Zork Screen, pt. 2](https://img.cleberg.net/blog/20201229-zork/zork_02.png)
69 68
@@ -78,9 +77,9 @@ case or carried until you feel like you want to put things away.
78It's been quite a few years since I first played Zork, but I clearly remember 77It's been quite a few years since I first played Zork, but I clearly remember
79the late nights and bloodshot eyes that helped me find all the treasures. This 78the late nights and bloodshot eyes that helped me find all the treasures. This
80game is well worth the time and effort, even though the text-based aspect may be 79game is well worth the time and effort, even though the text-based aspect may be
81off-putting to gamers who didn't have to grow up playing games without 80off-putting to gamers who didn't have to grow up playing games without graphics.
82graphics. However, I believe that the strategy and skills learned in early video 81However, I believe that the strategy and skills learned in early video games
83games like Zork can actually help you, even when playing newer games. 82like Zork can actually help you, even when playing newer games.
84 83
85If you do decide to play Zork, you can download Zork I, II, and III from 84If you do decide to play Zork, you can download Zork I, II, and III from
86Infocom's [download page](http://infocom-if.org/downloads/downloads.html) for 85Infocom's [download page](http://infocom-if.org/downloads/downloads.html) for
content/blog/2021-01-01-seum.md +7 −7
@@ -47,13 +47,13 @@ existing orange portals, light all yellow beacons, avoid things like fireballs
47and blades, or use any satanic power orbs lying around. These special abilities 47and blades, or use any satanic power orbs lying around. These special abilities
48include: 48include:
49 49
50- Gravity 50- Gravity
51- Teleport 51- Teleport
52- Rewind 52- Rewind
53- Spawn platform 53- Spawn platform
54- Roar (DLC) 54- Roar (DLC)
55- Rocket (DLC) 55- Rocket (DLC)
56- Shadow world (DLC) 56- Shadow world (DLC)
57 57
58For the main storyline, there are nine floors to beat. Each floor contains nine 58For the main storyline, there are nine floors to beat. Each floor contains nine
59regular levels, one boss level, and one bonus level; although you don't 59regular levels, one boss level, and one bonus level; although you don't
content/blog/2021-01-04-fediverse.md +19 −19
@@ -34,13 +34,13 @@ users.
34This strategy is great for making sure control of the social web isn't 34This strategy is great for making sure control of the social web isn't
35controlled by a single organization, but it also has some downsides. If I create 35controlled by a single organization, but it also has some downsides. If I create
36a Mastodon instance and get a ton of users to sign up, I can shut the server 36a Mastodon instance and get a ton of users to sign up, I can shut the server
37down at any time. That means you're at risk of losing the content you've 37down at any time. That means you're at risk of losing the content you've created
38created unless you back it up, or the server backs it up for you. Also, 38unless you back it up, or the server backs it up for you. Also, depending on the
39depending on the software used (e.g. Mastodon, Pixelfed, etc.), censorship may 39software used (e.g. Mastodon, Pixelfed, etc.), censorship may still be an issue
40still be an issue if the server admins decide they want to censor their users. 40if the server admins decide they want to censor their users. Now, censorship
41Now, censorship isn't always a bad thing and can even benefit the community as 41isn't always a bad thing and can even benefit the community as a whole, but
42a whole, but you'll want to determine which servers align with your idea of 42you'll want to determine which servers align with your idea of proper
43proper censorship. 43censorship.
44 44
45However, these are risks that we take when we sign up for any online platform. 45However, these are risks that we take when we sign up for any online platform.
46Whatever your reason is for trying out federated social networks, they are part 46Whatever your reason is for trying out federated social networks, they are part
@@ -58,39 +58,39 @@ might just find the perfect home.
58 58
59## Reddit 59## Reddit
60 60
61- [Lemmy](https://lemmy.ml/instances) 61- [Lemmy](https://lemmy.ml/instances)
62 62
63## Twitter/Facebook/Tumblr 63## Twitter/Facebook/Tumblr
64 64
65- [Mastodon](https://joinmastodon.org) 65- [Mastodon](https://joinmastodon.org)
66- [Diaspora](https://diasporafoundation.org) 66- [Diaspora](https://diasporafoundation.org)
67- [Friendica](https://friendi.ca) 67- [Friendica](https://friendi.ca)
68- [GNU Social](https://gnusocial.network) 68- [GNU Social](https://gnusocial.network)
69- [Pleroma](https://pleroma.social) 69- [Pleroma](https://pleroma.social)
70 70
71## Instagram 71## Instagram
72 72
73- [Pixelfed](https://pixelfed.org) 73- [Pixelfed](https://pixelfed.org)
74 74
75## Slack/Discord 75## Slack/Discord
76 76
77- [Matrix](https://element.io) 77- [Matrix](https://element.io)
78 78
79## Youtube/Vimeo 79## Youtube/Vimeo
80 80
81- [Peertube](https://joinpeertube.org) 81- [Peertube](https://joinpeertube.org)
82 82
83## Spotify/Soundcloud 83## Spotify/Soundcloud
84 84
85- [Funkwhale](https://funkwhale.audio) 85- [Funkwhale](https://funkwhale.audio)
86 86
87## Podcasting 87## Podcasting
88 88
89- [Pubcast](https://pubcast.pub) 89- [Pubcast](https://pubcast.pub)
90 90
91## Medium/Blogger 91## Medium/Blogger
92 92
93- [WriteFreely](https://writefreely.org) 93- [WriteFreely](https://writefreely.org)
94 94
95# Get Started 95# Get Started
96 96
content/blog/2021-01-07-ufw.md +14 −14
@@ -9,8 +9,8 @@ draft = false
9 9
10Uncomplicated Firewall, also known as ufw, is a convenient and beginner-friendly 10Uncomplicated Firewall, also known as ufw, is a convenient and beginner-friendly
11way to enforce OS-level firewall rules. For those who are hosting servers or any 11way to enforce OS-level firewall rules. For those who are hosting servers or any
12device that is accessible to the world (i.e., by public IP or domain name), 12device that is accessible to the world (i.e., by public IP or domain name), it's
13it's critical that a firewall is properly implemented and active. 13critical that a firewall is properly implemented and active.
14 14
15Ufw is available by default in all Ubuntu installations after 8.04 LTS. For 15Ufw is available by default in all Ubuntu installations after 8.04 LTS. For
16other distributions, you can look to install ufw or check if there are 16other distributions, you can look to install ufw or check if there are
@@ -57,9 +57,9 @@ sudo ufw default allow outgoing
57 57
58# Adding Port Rules 58# Adding Port Rules
59 59
60Now that we've disabled all incoming traffic by default, we need to open up 60Now that we've disabled all incoming traffic by default, we need to open up some
61some ports (or else no traffic would be able to come in). If you need to be able 61ports (or else no traffic would be able to come in). If you need to be able to
62to `ssh` into the machine, you'll need to open up port 22. 62`ssh` into the machine, you'll need to open up port 22.
63 63
64```sh 64```sh
65sudo ufw allow 22 65sudo ufw allow 22
@@ -102,7 +102,7 @@ Now that the firewall is enabled, let's check and see what the rules look like.
102sudo ufw status numbered 102sudo ufw status numbered
103``` 103```
104 104
105``` txt 105```txt
106Status: active 106Status: active
107 107
108 To Action From 108 To Action From
@@ -114,8 +114,8 @@ Status: active
114# Deleting Rules 114# Deleting Rules
115 115
116If you need to delete a rule, you need to know the number associated with that 116If you need to delete a rule, you need to know the number associated with that
117rule. Let's delete the first rule in the table above. You'll be asked to 117rule. Let's delete the first rule in the table above. You'll be asked to confirm
118confirm the deletion as part of this process. 118the deletion as part of this process.
119 119
120```sh 120```sh
121sudo ufw delete 1 121sudo ufw delete 1
@@ -134,7 +134,7 @@ sudo ufw app list
134 134
135The results should look something like this: 135The results should look something like this:
136 136
137``` txt 137```txt
138Available applications: 138Available applications:
139 OpenSSH 139 OpenSSH
140 Samba 140 Samba
@@ -152,7 +152,7 @@ sudo ufw app info plexmediaserver-dlna
152 152
153You'll get a blurb of info back like this: 153You'll get a blurb of info back like this:
154 154
155``` txt 155```txt
156Profile: plexmediaserver-dlna 156Profile: plexmediaserver-dlna
157Title: Plex Media Server (DLNA) 157Title: Plex Media Server (DLNA)
158Description: The Plex Media Server (additional DLNA capability only) 158Description: The Plex Media Server (additional DLNA capability only)
@@ -182,7 +182,7 @@ make sure the content is properly formatted.
182For example, here are the contents my `plexmediaserver` file, which creates 182For example, here are the contents my `plexmediaserver` file, which creates
183three distinct app rules for ufw: 183three distinct app rules for ufw:
184 184
185``` config 185```config
186[plexmediaserver] 186[plexmediaserver]
187title=Plex Media Server (Standard) 187title=Plex Media Server (Standard)
188description=The Plex Media Server 188description=The Plex Media Server
@@ -199,14 +199,14 @@ description=The Plex Media Server (with additional DLNA capability)
199ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp 199ports=32400/tcp|3005/tcp|5353/udp|8324/tcp|32410:32414/udp|1900/udp|32469/tcp
200``` 200```
201 201
202So, if I wanted to create a custom app rule called "mycustomrule," I'd create 202So, if I wanted to create a custom app rule called "mycustomrule," I'd create a
203a file and add my content like this: 203file and add my content like this:
204 204
205```sh 205```sh
206sudo nano /etc/ufw/applications.d/mycustomrule 206sudo nano /etc/ufw/applications.d/mycustomrule
207``` 207```
208 208
209``` config 209```config
210[mycustomrule] 210[mycustomrule]
211title=My Custom Rule 211title=My Custom Rule
212description=This is a temporary ufw app rule. 212description=This is a temporary ufw app rule.
content/blog/2021-02-19-macos.md +4 −4
@@ -29,7 +29,7 @@ The desktop itself reminds me of GNOME more than anything else I've seen: even
29Pantheon from [ElementaryOS](https://elementary.io/), which people commonly 29Pantheon from [ElementaryOS](https://elementary.io/), which people commonly
30refer to as the closest Linux distro to macOS. The desktop toolbar is great and 30refer to as the closest Linux distro to macOS. The desktop toolbar is great and
31far surpasses the utility of the GNOME toolbar due to the fact that the 31far surpasses the utility of the GNOME toolbar due to the fact that the
32extensions and icons *actually work*. I launch macOS and immediately see my 32extensions and icons _actually work_. I launch macOS and immediately see my
33shortcuts for Tresorit, Bitwarden, and Mullvad pop up as the computer loads. 33shortcuts for Tresorit, Bitwarden, and Mullvad pop up as the computer loads.
34 34
35Even further, the app dock is very useful and will be yet another familiarity 35Even further, the app dock is very useful and will be yet another familiarity
@@ -171,9 +171,9 @@ want](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes), save the file, and exit.
171ZSH_THEME="af-magic" 171ZSH_THEME="af-magic"
172``` 172```
173 173
174After changing the `.zshrc` file, you'll need to close your terminal and 174After changing the `.zshrc` file, you'll need to close your terminal and re-open
175re-open it to see the changes. Optionally, just open a new tab if you're using 175it to see the changes. Optionally, just open a new tab if you're using iTerm2,
176iTerm2, and you'll see the new shell config. 176and you'll see the new shell config.
177 177
178# Oh-My-Zsh Plugins 178# Oh-My-Zsh Plugins
179 179
content/blog/2021-03-19-clone-github-repos.md +4 −4
@@ -20,8 +20,8 @@ nano clone_github_repos.sh
20``` 20```
21 21
22Next, paste in the following information. Note that you can replace the word 22Next, paste in the following information. Note that you can replace the word
23`users` in the first line with `orgs` and type an organization's name instead 23`users` in the first line with `orgs` and type an organization's name instead of
24of a user's name. 24a user's name.
25 25
26```sh 26```sh
27CNTX=users; NAME=YOUR-USERNAME; PAGE=1 27CNTX=users; NAME=YOUR-USERNAME; PAGE=1
@@ -45,8 +45,8 @@ Now you can run the script and should see the cloning process begin.
45 45
46# Cloning from Sourcehut 46# Cloning from Sourcehut
47 47
48I haven't fully figured out how to directly incorporate Sourcehut's GraphQL 48I haven't fully figured out how to directly incorporate Sourcehut's GraphQL API
49API into a bash script yet, so this one will take two steps. 49into a bash script yet, so this one will take two steps.
50 50
51First, log-in to Sourcehut and go to their [GraphQL playground for 51First, log-in to Sourcehut and go to their [GraphQL playground for
52Git](https://git.sr.ht/graphql). Next, paste the following query into the left 52Git](https://git.sr.ht/graphql). Next, paste the following query into the left
content/blog/2021-03-28-gemini-capsule.md +18 −18
@@ -8,21 +8,21 @@ draft = false
8# What is Gemini? 8# What is Gemini?
9 9
10[Gemini](https://gemini.circumlunar.space/) is an internet protocol introduced 10[Gemini](https://gemini.circumlunar.space/) is an internet protocol introduced
11in June 2019 as an alternative to HTTP(S) or Gopher. In layman's terms, it's 11in June 2019 as an alternative to HTTP(S) or Gopher. In layman's terms, it's an
12an alternative way to browse sites (called capsules) that requires a special 12alternative way to browse sites (called capsules) that requires a special
13browser. Since Gemini is not standardized as an internet standard, normal web 13browser. Since Gemini is not standardized as an internet standard, normal web
14browsers won't be able to load a Gemini capsule. Instead, you'll need to use 14browsers won't be able to load a Gemini capsule. Instead, you'll need to use [a
15[a Gemini-specific browser](https://gemini.%20circumlunar.space/clients.html). 15Gemini-specific browser](https://gemini.%20circumlunar.space/clients.html).
16 16
17The content found within a Gemini page is called 17The content found within a Gemini page is called
18[Gemtext](https://gemini.circumlunar.space/docs/cheatsheet.gmi) and is 18[Gemtext](https://gemini.circumlunar.space/docs/cheatsheet.gmi) and is
19*extremely* basic (on purpose). Gemini only processes the text, no media content 19_extremely_ basic (on purpose). Gemini only processes the text, no media content
20like images. However, you're able to style 3 levels of headings, regular text, 20like images. However, you're able to style 3 levels of headings, regular text,
21links (which will display on their own line), quotes, and an unordered list. 21links (which will display on their own line), quotes, and an unordered list.
22 22
23Here's a complete listing of valid Gemtext: 23Here's a complete listing of valid Gemtext:
24 24
25``` txt 25````txt
26# Heading 1 26# Heading 1
27## Heading 2 27## Heading 2
28### Heading 3 28### Heading 3
@@ -39,7 +39,7 @@ My List:
39** Item 39** Item
40 40
41```Anything between three backticks will be rendered as code.``` 41```Anything between three backticks will be rendered as code.```
42``` 42````
43 43
44### Free Option 44### Free Option
45 45
@@ -87,8 +87,8 @@ tools, but mostly surrounds their hosted Git repository service. Simply put,
87it's a minimal and more private alternative to services like GitHub. 87it's a minimal and more private alternative to services like GitHub.
88 88
89This walkthrough is more advanced and involves things like Git, SSH, the command 89This walkthrough is more advanced and involves things like Git, SSH, the command
90line. If you don't think you know enough to do this, check out my walkthrough 90line. If you don't think you know enough to do this, check out my walkthrough on
91on creating a Gemini capsule for the Midnight Pub instead. 91creating a Gemini capsule for the Midnight Pub instead.
92 92
93The first thing you'll need to do is create an SSH key pair, if you don't 93The first thing you'll need to do is create an SSH key pair, if you don't
94already have one on your system. Once created, grab the contents of `id_rsa.pub` 94already have one on your system. Once created, grab the contents of `id_rsa.pub`
@@ -107,8 +107,8 @@ format exactly:
107mkdir your-username.srht.site && cd your-username.srht.site 107mkdir your-username.srht.site && cd your-username.srht.site
108``` 108```
109 109
110Now that we've created the repo, let's initialize Git and add the proper 110Now that we've created the repo, let's initialize Git and add the proper remote
111remote URL. 111URL.
112 112
113```sh 113```sh
114git init 114git init
@@ -121,13 +121,13 @@ git remote add origin git@git.sr.ht:~your-username/your-username.srht.site
121Now that our repository is set up and configured, we will need to create at 121Now that our repository is set up and configured, we will need to create at
122least two files: 122least two files:
123 123
124- `index.gmi` 124- `index.gmi`
125- `.build.yml` 125- `.build.yml`
126 126
127For your `.build.yml` file, use the following content and be sure to update the 127For your `.build.yml` file, use the following content and be sure to update the
128`site` line with your username! 128`site` line with your username!
129 129
130``` yaml 130```yaml
131image: alpine/latest 131image: alpine/latest
132oauth: pages.sr.ht/PAGES:RW 132oauth: pages.sr.ht/PAGES:RW
133environment: 133environment:
@@ -146,7 +146,7 @@ even just copy and paste the Gemtext cheatsheet.
146If you want to serve both HTML and Gemini files from this repository, just add a 146If you want to serve both HTML and Gemini files from this repository, just add a
147second command to the `upload` section: 147second command to the `upload` section:
148 148
149``` yaml 149```yaml
150- upload: | 150- upload: |
151 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI 151 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz -Fprotocol=GEMINI
152 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz 152 acurl -f https://pages.sr.ht/publish/$site -Fcontent=@site.tar.gz
@@ -158,9 +158,9 @@ Lastly, commit your changes and push them to the remote repo.
158git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD 158git add .; git commit -m "initial commit"; git push --set-upstream origin HEAD
159``` 159```
160 160
161If you've successfully created the files with the proper format, you'll see 161If you've successfully created the files with the proper format, you'll see the
162the terminal print a message that lets you know where the automatic build is 162terminal print a message that lets you know where the automatic build is taking
163taking place. For example, here's what the terminal tells me: 163place. For example, here's what the terminal tells me:
164 164
165```sh 165```sh
166remote: Build started: 166remote: Build started:
content/blog/2021-03-28-vaporwave-vs-outrun.md +2 −2
@@ -47,8 +47,8 @@ specific aspects that make Vaporwave unique:
47 47
48The time frame for references, logos, etc. focuses mostly on the 1990s in 48The time frame for references, logos, etc. focuses mostly on the 1990s in
49Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, tropical 49Vaporwave. You'll see old school Pepsi logos, Microsoft 95 screens, tropical
50plants, classic marble sculptures, and many references from Japan's influence 50plants, classic marble sculptures, and many references from Japan's influence in
51in the 90s. 51the 90s.
52 52
53## Art 53## Art
54 54
content/blog/2021-03-30-vps-web-server.md +27 −28
@@ -85,9 +85,9 @@ increase the resources at any time.
85# Configuring DNS Settings 85# Configuring DNS Settings
86 86
87Okay, so now let's get into some actual work that has to be done to get content 87Okay, so now let's get into some actual work that has to be done to get content
88moved from a shared host to a VPS. At this point, I'm assuming you have a 88moved from a shared host to a VPS. At this point, I'm assuming you have a shared
89shared host with website content that you can still access, and you've 89host with website content that you can still access, and you've purchased a new
90purchased a new VPS and can SSH into that server. 90VPS and can SSH into that server.
91 91
92The first change is minor, but it should be done immediately in order to get 92The first change is minor, but it should be done immediately in order to get
93things moving: DNS settings. Go to wherever your DNS settings are handled. If 93things moving: DNS settings. Go to wherever your DNS settings are handled. If
@@ -98,15 +98,15 @@ DNS over to your new VPS provider. For me, I route my DNS through
98Once you know where your DNS settings are, go ahead and update the `A` records 98Once you know where your DNS settings are, go ahead and update the `A` records
99to match the public IP address of your VPS. For example: 99to match the public IP address of your VPS. For example:
100 100
101``` txt 101```txt
102A example.com xxx.xxx.xxx.xxx 102A example.com xxx.xxx.xxx.xxx
103A subdomain xxx.xxx.xxx.xxx 103A subdomain xxx.xxx.xxx.xxx
104CNAME www example.com. 104CNAME www example.com.
105``` 105```
106 106
107If you have any other records that require updates, such as MX or TXT records 107If you have any other records that require updates, such as MX or TXT records
108for a mail server, be sure to update those accordingly. Personally, I don't 108for a mail server, be sure to update those accordingly. Personally, I don't host
109host my own mail server. I route all mail on my custom domains to 109my own mail server. I route all mail on my custom domains to
110[Migadu](https://www.migadu.com). Hosting your own email server can become 110[Migadu](https://www.migadu.com). Hosting your own email server can become
111complex quickly and is not for beginners. 111complex quickly and is not for beginners.
112 112
@@ -132,8 +132,8 @@ set it up.
132 132
133First, let's update and upgrade our server. 133First, let's update and upgrade our server.
134 134
135**NOTE:** Since we have logged in to the server as `root` for now, we don't 135**NOTE:** Since we have logged in to the server as `root` for now, we don't need
136need to use the `sudo` modifier before our commands. 136to use the `sudo` modifier before our commands.
137 137
138```sh 138```sh
139apt update && apt upgrade -y 139apt update && apt upgrade -y
@@ -173,8 +173,8 @@ from the VPS):
173ssh-copy-id testuser@xxx.xxx.xxx.xxx 173ssh-copy-id testuser@xxx.xxx.xxx.xxx
174``` 174```
175 175
176If you've disabled password-based SSH, you'll need to manually copy your SSH 176If you've disabled password-based SSH, you'll need to manually copy your SSH key
177key into the `~/.ssh/authorized_keys` file. 177into the `~/.ssh/authorized_keys` file.
178 178
179# Install Software 179# Install Software
180 180
@@ -209,9 +209,9 @@ sudo mkdir example.com
209``` 209```
210 210
211We have a folder for `example.com` now, so let's add an `index.html` file and 211We have a folder for `example.com` now, so let's add an `index.html` file and
212put it within a specific `public_html` folder. You don't need this 212put it within a specific `public_html` folder. You don't need this `public_html`
213`public_html` if you don't want it, but it helps with organizing items related 213if you don't want it, but it helps with organizing items related to
214to `example.com` that you don't want to publish to the internet. 214`example.com` that you don't want to publish to the internet.
215 215
216```sh 216```sh
217cd example.com 217cd example.com
@@ -222,23 +222,22 @@ sudo nano index.html
222You can put anything you want in this `index.html` file. If you can't think of 222You can put anything you want in this `index.html` file. If you can't think of
223anything, paste this in there: 223anything, paste this in there:
224 224
225``` html 225```html
226<!DOCTYPE html> 226<!DOCTYPE html>
227<html lang="en"> 227<html lang="en">
228 <head> 228 <head>
229 <meta charset="utf-8" /> 229 <meta charset="utf-8" />
230 <meta name="viewport" content="width=device-width, initial-scale=1" /> 230 <meta name="viewport" content="width=device-width, initial-scale=1" />
231 <title>Hello, world!</title> 231 <title>Hello, world!</title>
232 </head> 232 </head>
233 <body> 233 <body>
234 <h1>Hello, world!</h1> 234 <h1>Hello, world!</h1>
235 </body> 235 </body>
236</html> 236</html>
237``` 237```
238 238
239If you want something to be served at `example.com/page01/file.txt`, you'll 239If you want something to be served at `example.com/page01/file.txt`, you'll have
240have to create the `page01` directory under the `example.com` directory. For 240to create the `page01` directory under the `example.com` directory. For example:
241example:
242 241
243```sh 242```sh
244cd /var/www/example.com/public_html 243cd /var/www/example.com/public_html
@@ -261,7 +260,7 @@ sudo nano example.com.conf
261This configuration file will have a few default lines, but you'll need to edit 260This configuration file will have a few default lines, but you'll need to edit
262it to look similar to this (settings may change based on your personal needs): 261it to look similar to this (settings may change based on your personal needs):
263 262
264``` config 263```config
265<VirtualHost *:80> 264<VirtualHost *:80>
266 ServerAdmin your-email@email-provider.com 265 ServerAdmin your-email@email-provider.com
267 ServerName example.com 266 ServerName example.com
@@ -290,8 +289,8 @@ sudo apache2ctl configtest
290 289
291Now, restart the web server entirely. After this, you should be able to browse 290Now, restart the web server entirely. After this, you should be able to browse
292to `http://example.com` and see the HTML content you provided earlier. Note that 291to `http://example.com` and see the HTML content you provided earlier. Note that
293SSL/TLS has not been enabled yet, so you won't be able to use the secure 292SSL/TLS has not been enabled yet, so you won't be able to use the secure version
294version yet (`https://example.com`). 293yet (`https://example.com`).
295 294
296```sh 295```sh
297sudo systemctl restart apache2 296sudo systemctl restart apache2
content/blog/2021-04-17-gemini-server.md +11 −12
@@ -76,9 +76,9 @@ sudo ./install.sh
76# Configure the Gemini Service 76# Configure the Gemini Service
77 77
78We have a little more to do, but since this script tries to immediately run the 78We have a little more to do, but since this script tries to immediately run the
79service, it will likely fail with an exit code. Let's add our finishing 79service, it will likely fail with an exit code. Let's add our finishing touches.
80touches. Edit the following file and replace the hostname with your desired URL. 80Edit the following file and replace the hostname with your desired URL. You can
81You can also change the directory where content will be served. 81also change the directory where content will be served.
82 82
83```sh 83```sh
84sudo nano /etc/systemd/system/gemini.service 84sudo nano /etc/systemd/system/gemini.service
@@ -130,19 +130,18 @@ sudo ufw reload
130 130
131# Creating Content 131# Creating Content
132 132
133Let's create the Gemini capsule. Note that wherever you set the 133Let's create the Gemini capsule. Note that wherever you set the WorkingDirectory
134WorkingDirectory variable to earlier, Agate will expect you to put your Gemini 134variable to earlier, Agate will expect you to put your Gemini capsule contents
135capsule contents in a sub-folder called "content." So, I place my files in 135in a sub-folder called "content." So, I place my files in "/var/gmi/content."
136"/var/gmi/content." I'm going to create that folder now and put a file in 136I'm going to create that folder now and put a file in there.
137there.
138 137
139```sh 138```sh
140sudo mkdir /var/gemini/content 139sudo mkdir /var/gemini/content
141sudo nano /var/gemini/content/index.gmi 140sudo nano /var/gemini/content/index.gmi
142``` 141```
143 142
144You can put whatever you want in the "index.gmi" file, just make sure it's 143You can put whatever you want in the "index.gmi" file, just make sure it's valid
145valid Gemtext. 144Gemtext.
146 145
147# The Results 146# The Results
148 147
@@ -153,9 +152,9 @@ Here are some screenshots of the Gemini page I just created in the
153![GUI Gemini 152![GUI Gemini
154browser](https://img.cleberg.net/blog/20210417-hosting-a-gemini-server/lagrange.png) 153browser](https://img.cleberg.net/blog/20210417-hosting-a-gemini-server/lagrange.png)
155 154
156*Lagrange* 155_Lagrange_
157 156
158![CLI Gemini 157![CLI Gemini
159browser](https://img.cleberg.net/blog/20210417-hosting-a-gemini-server/amfora.png) 158browser](https://img.cleberg.net/blog/20210417-hosting-a-gemini-server/amfora.png)
160 159
161*Amfora* 160_Amfora_
content/blog/2021-04-23-php-comment-system.md +60 −60
@@ -16,15 +16,15 @@ that should be standard.
16 16
17Of course, there are some really terrible options: 17Of course, there are some really terrible options:
18 18
19- Facebook Comments 19- Facebook Comments
20- Discourse 20- Discourse
21 21
22There are some options that are better but still use too many scripts, frames, 22There are some options that are better but still use too many scripts, frames,
23or social integrations on your web page that could impact some users: 23or social integrations on your web page that could impact some users:
24 24
25- Disqus 25- Disqus
26- Isso 26- Isso
27- Remark42 27- Remark42
28 28
29Lastly, I looked into a few unique ways of generating blog comments, such as 29Lastly, I looked into a few unique ways of generating blog comments, such as
30using Twitter threads or GitHub issues to automatically post issues. However, 30using Twitter threads or GitHub issues to automatically post issues. However,
@@ -52,22 +52,22 @@ database for any other part of my websites.
52I blog in plain Markdown files, commit all articles to Git, and ensure that 52I blog in plain Markdown files, commit all articles to Git, and ensure that
53future readers will be able to see the source data long after I'm gone, or the 53future readers will be able to see the source data long after I'm gone, or the
54website has gone offline. However, I still haven't committed any images served 54website has gone offline. However, I still haven't committed any images served
55on my blog to Git, as I'm not entirely sold on Git LFS yet - for now, images 55on my blog to Git, as I'm not entirely sold on Git LFS yet - for now, images can
56can be found at [img.cleberg.net](https://img.cleberg.net). 56be found at [img.cleberg.net](https://img.cleberg.net).
57 57
58Saving my comments back to the Git repository ensures that another aspect of my 58Saving my comments back to the Git repository ensures that another aspect of my
59site will degrade gracefully. 59site will degrade gracefully.
60 60
61# Create a Comment Form 61# Create a Comment Form
62 62
63Okay, let's get started. The first step is to create an HTML form that users 63Okay, let's get started. The first step is to create an HTML form that users can
64can see and utilize to submit comments. This is fairly easy and can be changed 64see and utilize to submit comments. This is fairly easy and can be changed
65depending on your personal preferences. 65depending on your personal preferences.
66 66
67Take a look at the code block below for the form I currently use. Note that 67Take a look at the code block below for the form I currently use. Note that
68`<current-url>` is replaced automatically in PHP with the current post's URL, 68`<current-url>` is replaced automatically in PHP with the current post's URL, so
69so that my PHP script used later will know which blog post the comment is 69that my PHP script used later will know which blog post the comment is related
70related to. 70to.
71 71
72The form contains the following structure: 72The form contains the following structure:
73 73
@@ -81,45 +81,45 @@ The form contains the following structure:
81 Markdown is allowed. 81 Markdown is allowed.
825. `<button>` - A button to submit the form. 825. `<button>` - A button to submit the form.
83 83
84``` html 84```html
85<form action="/comment.php" method="POST"> 85<form action="/comment.php" method="POST">
86 <h3>Leave a Comment</h3> 86 <h3>Leave a Comment</h3>
87 <section hidden> 87 <section hidden>
88 <label class="form-label" for="postURL">Post URL</label> 88 <label class="form-label" for="postURL">Post URL</label>
89 <input 89 <input
90 class="form-control" 90 class="form-control"
91 id="postURL" 91 id="postURL"
92 name="postURL" 92 name="postURL"
93 type="text" 93 type="text"
94 value="<current-url>" 94 value="<current-url>"
95 /> 95 />
96 </section> 96 </section>
97 <section> 97 <section>
98 <label class="form-label" for="userName">Display Name</label> 98 <label class="form-label" for="userName">Display Name</label>
99 <input 99 <input
100 class="form-control" 100 class="form-control"
101 id="userName" 101 id="userName"
102 name="userName" 102 name="userName"
103 placeholder="John Doe" 103 placeholder="John Doe"
104 type="text" 104 type="text"
105 /> 105 />
106 </section> 106 </section>
107 <section> 107 <section>
108 <label class="form-label" for="userContent">Your Comment</label> 108 <label class="form-label" for="userContent">Your Comment</label>
109 <textarea 109 <textarea
110 class="form-control" 110 class="form-control"
111 id="userContent" 111 id="userContent"
112 name="userContent" 112 name="userContent"
113 rows="3" 113 rows="3"
114 placeholder="# Feel free to use Markdown" 114 placeholder="# Feel free to use Markdown"
115 aria-describedby="commentHelp" 115 aria-describedby="commentHelp"
116 required 116 required
117 ></textarea> 117 ></textarea>
118 <div id="commentHelp" class="form-text"> 118 <div id="commentHelp" class="form-text">
119 Comments are saved as Markdown and cannot be edited or deleted. 119 Comments are saved as Markdown and cannot be edited or deleted.
120 </div> 120 </div>
121 </section> 121 </section>
122 <button type="submit">Submit</button> 122 <button type="submit">Submit</button>
123</form> 123</form>
124``` 124```
125 125
@@ -144,7 +144,7 @@ the following tasks in this script:
1448. Finally, send the user back to the `#comments` section of the blog post they 1448. Finally, send the user back to the `#comments` section of the blog post they
145 just read. 145 just read.
146 146
147``` php 147```php
148// Get the content sent from the comment form 148// Get the content sent from the comment form
149$comment = htmlentities($_POST['userContent']); 149$comment = htmlentities($_POST['userContent']);
150$post_url = $_POST['postURL']; 150$post_url = $_POST['postURL'];
@@ -202,7 +202,7 @@ This piece of code should **really** be inside a function (or at least in an
202organized PHP workflow). Don't just copy-and-paste and expect it to work. You 202organized PHP workflow). Don't just copy-and-paste and expect it to work. You
203need to at least supply a `$query` variable depending on the page visited. 203need to at least supply a `$query` variable depending on the page visited.
204 204
205``` php 205```php
206$query = 'your-blog-post.html'; 206$query = 'your-blog-post.html';
207 207
208// Load saved comments 208// Load saved comments
@@ -251,11 +251,11 @@ make sure it is printed when someone visits `https://example.com/comments/`.
251This comment system is by no means a fully-developed system. I have noted a few 251This comment system is by no means a fully-developed system. I have noted a few
252possible enhancements here that I may implement in the future: 252possible enhancements here that I may implement in the future:
253 253
254- Create a secure moderator page with user authentication at 254- Create a secure moderator page with user authentication at
255 `https://blog.example.com/mod/`. This page could have the option to edit or 255 `https://blog.example.com/mod/`. This page could have the option to edit or
256 delete any comment found in `comments.json`. 256 delete any comment found in `comments.json`.
257- Create a temporary file, such as `pending_comments.json`, that will store 257- Create a temporary file, such as `pending_comments.json`, that will store
258 newly-submitted comments and won't display on blog posts until approved by a 258 newly-submitted comments and won't display on blog posts until approved by a
259 moderator. 259 moderator.
260- Create a `/modlog/` page with a chronological log, showing which moderator 260- Create a `/modlog/` page with a chronological log, showing which moderator
261 approved which comments and why certain comments were rejected. 261 approved which comments and why certain comments were rejected.
content/blog/2021-04-28-photography.md +4 −4
@@ -48,10 +48,10 @@ perfect for me.
48For lenses, I decided to buy two lenses that could carry me through most 48For lenses, I decided to buy two lenses that could carry me through most
49situations: 49situations:
50 50
51- [Vario-Tessar T** FE 24-70 mm F4 ZA 51- [Vario-Tessar T\*\* FE 24-70 mm F4 ZA
52 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z) 52 OSS](https://electronics.sony.com/imaging/lenses/full-frame-e-mount/p/sel2470z)
53- [Tamron 70-300mm f4.5-6.3 Di III 53- [Tamron 70-300mm f4.5-6.3 Di III
54 RXD](https://www.tamron-usa.com/product/lenses/a047.html) 54 RXD](https://www.tamron-usa.com/product/lenses/a047.html)
55 55
56In addition, I grabbed a couple [HGX Prime 56In addition, I grabbed a couple [HGX Prime
5767mm](https://www.promaster.com/Product/6725) protection filters for the lenses. 5767mm](https://www.promaster.com/Product/6725) protection filters for the lenses.
content/blog/2021-05-30-changing-git-authors.md +3 −3
@@ -23,9 +23,9 @@ nano change_git_authors.sh
23The following information can be pasted directly into your bash script. The only 23The following information can be pasted directly into your bash script. The only
24changes you need to make are to the following variables: 24changes you need to make are to the following variables:
25 25
26- `OLD_EMAIL` 26- `OLD_EMAIL`
27- `CORRECT_NAME` 27- `CORRECT_NAME`
28- `CORRECT_EMAIL` 28- `CORRECT_EMAIL`
29 29
30```sh 30```sh
31#!/bin/sh 31#!/bin/sh
content/blog/2021-07-15-delete-gitlab-repos.md +3 −3
@@ -47,7 +47,7 @@ nano main.py
47 47
48Enter the following code into your `main.py` script. 48Enter the following code into your `main.py` script.
49 49
50``` python 50```python
51import request 51import request
52import json 52import json
53 53
@@ -107,8 +107,8 @@ Now that you have the proper information, replace `{user-id}` with your GitLab
107username and `{auth-token}` with the authorization token you created earlier. 107username and `{auth-token}` with the authorization token you created earlier.
108 108
109Finally, simply run the script and watch the output. You can also use PyCharm 109Finally, simply run the script and watch the output. You can also use PyCharm
110Community Edition to edit and run the Python script if you don't want to work 110Community Edition to edit and run the Python script if you don't want to work in
111in a terminal. 111a terminal.
112 112
113```sh 113```sh
114python3 main.py 114python3 main.py
content/blog/2021-08-25-audit-sampling.md +20 −21
@@ -46,7 +46,7 @@ Now that you know what you're using, you can always check out the code behind
46`pandas.DataFrame.sample`. This function does a lot of work, but we really only 46`pandas.DataFrame.sample`. This function does a lot of work, but we really only
47care about the following snippets of code: 47care about the following snippets of code:
48 48
49``` python 49```python
50# Process random_state argument 50# Process random_state argument
51rs = com.random_state(random_state) 51rs = com.random_state(random_state)
52 52
@@ -64,9 +64,9 @@ The block of code above shows you that if you assign a `random_state` argument
64when you run the function, that will be used as a seed number in the random 64when you run the function, that will be used as a seed number in the random
65generation and will allow you to reproduce a sample, given that nothing else 65generation and will allow you to reproduce a sample, given that nothing else
66changes. This is critical to the posterity of audit work. After all, how can you 66changes. This is critical to the posterity of audit work. After all, how can you
67say your audit process is adequately documented if the next person can't run 67say your audit process is adequately documented if the next person can't run the
68the code and get the same sample? The final piece here on randomness is to look 68code and get the same sample? The final piece here on randomness is to look at
69at the [choice](https://docs.%20python.org/3/library/random.html#random.choice) 69the [choice](https://docs.%20python.org/3/library/random.html#random.choice)
70function used above. This is the crux of the generation and can also be examined 70function used above. This is the crux of the generation and can also be examined
71for more detailed analysis on its reliability. As far as auditing goes, we will 71for more detailed analysis on its reliability. As far as auditing goes, we will
72trust that these functions are mathematically random. 72trust that these functions are mathematically random.
@@ -90,23 +90,22 @@ that will instruct auditors which sample sizes to choose. This allows for
90uniform testing and reduces overall workload. See the table below for a common 90uniform testing and reduces overall workload. See the table below for a common
91implementation of sample sizes: 91implementation of sample sizes:
92 92
93 Control Frequency Sample Size - High Risk Sample Size - Low Risk 93Control Frequency Sample Size - High Risk Sample Size - Low Risk
94 ------------------- ------------------------- ------------------------ 94
95 More Than Daily 40 25 Daily 40 95---
96 25 Weekly 12 5 Monthly 5 96
97 3 Quarterly 2 2 Semi-Annually 1 97More Than Daily 40 25 Daily 40 25 Weekly 12 5 Monthly 5 3 Quarterly 2 2
98 1 Annually 1 1 Ad-hoc 1 98Semi-Annually 1 1 Annually 1 1 Ad-hoc 1 1
99 1
100 99
101### Sampling with Python & Pandas 100### Sampling with Python & Pandas
102 101
103In this section, I am going to cover a few basic audit situations that require 102In this section, I am going to cover a few basic audit situations that require
104sampling. While some situations may require more effort, the syntax, 103sampling. While some situations may require more effort, the syntax,
105organization, and intellect used remain largely the same. If you've never used 104organization, and intellect used remain largely the same. If you've never used
106Python before, note that lines starting with a '`#`' symbol are called 105Python before, note that lines starting with a '`#`' symbol are called comments,
107comments, and they will be skipped by Python. I highly recommend taking a quick 106and they will be skipped by Python. I highly recommend taking a quick tutorial
108tutorial online to understand the basics of Python if any of the code below is 107online to understand the basics of Python if any of the code below is confusing
109confusing to you. 108to you.
110 109
111## Simple Random Sample 110## Simple Random Sample
112 111
@@ -114,7 +113,7 @@ First, let's look at a simple, random sample. The code block below will import
114the `pandas` module, load a data file, sample the data, and export the sample to 113the `pandas` module, load a data file, sample the data, and export the sample to
115a file. 114a file.
116 115
117``` python 116```python
118# Import the Pandas module 117# Import the Pandas module
119import pandas 118import pandas
120 119
@@ -139,7 +138,7 @@ sample.to_excel(file_output)
139Now that we've created a simple sample, let's create a sample from multiple 138Now that we've created a simple sample, let's create a sample from multiple
140files. 139files.
141 140
142``` python 141```python
143# Import the Pandas module 142# Import the Pandas module
144import pandas 143import pandas
145 144
@@ -171,10 +170,10 @@ sample.to_excel(file_output)
171## Stratified Random Sample 170## Stratified Random Sample
172 171
173Well, what if you need to sample distinct parts of a single file? For example, 172Well, what if you need to sample distinct parts of a single file? For example,
174let's write some code to separate our data by "Region" and sample those 173let's write some code to separate our data by "Region" and sample those regions
175regions independently. 174independently.
176 175
177``` python 176```python
178# Import the Pandas module 177# Import the Pandas module
179import pandas 178import pandas
180 179
@@ -209,7 +208,7 @@ period. This code will generate samples for each month in the data and combine
209them all together at the end. Obviously, this code can be modified to stratify 208them all together at the end. Obviously, this code can be modified to stratify
210by something other than months, if needed. 209by something other than months, if needed.
211 210
212``` python 211```python
213# Import the Pandas module 212# Import the Pandas module
214import pandas 213import pandas
215 214
content/blog/2021-10-09-apache-redirect.md +4 −4
@@ -24,10 +24,10 @@ To solve this problem, I really needed to solve two pieces:
24 `/blog/some-post/`. 24 `/blog/some-post/`.
252. Ensure that no other `.html` files are redirected, such as `index.html`. 252. Ensure that no other `.html` files are redirected, such as `index.html`.
26 26
27After *a lot* of tweaking and testing, I believe I have finally found the 27After _a lot_ of tweaking and testing, I believe I have finally found the
28solution. The solution is shown below. 28solution. The solution is shown below.
29 29
30``` conf 30```conf
31RewriteEngine On 31RewriteEngine On
32RewriteCond %{REQUEST_URI} !\index.html$ [NC] 32RewriteCond %{REQUEST_URI} !\index.html$ [NC]
33RewriteRule ^(.*).html$ https://example.com/$1 [R=301,L] 33RewriteRule ^(.*).html$ https://example.com/$1 [R=301,L]
@@ -41,5 +41,5 @@ following:
413. Find any `.html` files within the website directory and redirect it to 413. Find any `.html` files within the website directory and redirect it to
42 exclude the file extension. 42 exclude the file extension.
434. The final piece is adding the trailing slash (`/`) at the end of the URL - 434. The final piece is adding the trailing slash (`/`) at the end of the URL -
44 you'll notice that I don't have an Apache rule for that since Apache 44 you'll notice that I don't have an Apache rule for that since Apache handles
45 handles that automatically. 45 that automatically.
content/blog/2021-12-04-cisa.md +14 −15
@@ -25,7 +25,7 @@ hired, getting a raise/bonus, or earning respect in the field.
25However, to be honest, I am a skeptic of most certifications. I understand the 25However, to be honest, I am a skeptic of most certifications. I understand the
26value they hold in terms of how much you need to commit to studying or learning 26value they hold in terms of how much you need to commit to studying or learning
27on the job, as well as the market value for certifications such as the CISA. But 27on the job, as well as the market value for certifications such as the CISA. But
28I also have known some very ~~incompetent~~ *less than stellar* auditors who 28I also have known some very ~~incompetent~~ _less than stellar_ auditors who
29have CPAs, CISAs, CIAs, etc. 29have CPAs, CISAs, CIAs, etc.
30 30
31The same goes for most industries: if a person is good at studying, they can 31The same goes for most industries: if a person is good at studying, they can
@@ -49,7 +49,7 @@ sections](https://img.cleberg.net/blog/20211204-i-passed-the-cisa/cisa-exam-sect
49Since the exam contains 150 questions, here's how those sections break down: 49Since the exam contains 150 questions, here's how those sections break down:
50 50
51| Exam Section | Percentage of Exam | Questions | 51| Exam Section | Percentage of Exam | Questions |
52|-----------------|--------------------|-----------| 52| --------------- | ------------------ | --------- |
53| 1 | 21% | 32 | 53| 1 | 21% | 32 |
54| 2 | 17% | 26 | 54| 2 | 17% | 26 |
55| 3 | 12% | 18 | 55| 3 | 12% | 18 |
@@ -68,19 +68,18 @@ Let me approach this from a few different viewpoints.
68 68
69## Study Materials 69## Study Materials
70 70
71Let's start by discussing the study materials I purchased. I'll be referring 71Let's start by discussing the study materials I purchased. I'll be referring to
72to #1 as the CRM and #2 as the QAE. 72#1 as the CRM and #2 as the QAE.
73 73
741. [CISA Review Manual, 27th Edition | 741. [CISA Review Manual, 27th Edition |
75Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK) 75 Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCbEAK)
762. [CISA Review Questions, Answers & Explanations Manual, 12th Edition | 762. [CISA Review Questions, Answers & Explanations Manual, 12th Edition |
77Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK) 77 Print](https://store.isaca.org/s/store#/store/browse/detail/a2S4w000004KoCcEAK)
78 78
79The CRM is an excellent source of information and could honestly be used as a 79The CRM is an excellent source of information and could honestly be used as a
80reference for most IS auditors as a learning reference during their daily audit 80reference for most IS auditors as a learning reference during their daily audit
81responsibilities. However, it is **full** of information and can be 81responsibilities. However, it is **full** of information and can be overloading
82overloading if you're not good at filtering out useless information while 82if you're not good at filtering out useless information while studying.
83studying.
84 83
85The QAE is the real star of the show here. This book contains 1000 questions, 84The QAE is the real star of the show here. This book contains 1000 questions,
86separated by exam section, and a practice exam. My only complaint about the QAE 85separated by exam section, and a practice exam. My only complaint about the QAE
@@ -117,7 +116,7 @@ from the QAE manual and scored 70% (105/150).
117Here's a breakdown of my initial practice exam: 116Here's a breakdown of my initial practice exam:
118 117
119| Exam Section | Incorrect | Correct | Grand Total | Percent | 118| Exam Section | Incorrect | Correct | Grand Total | Percent |
120|-----------------|-----------|---------|-------------|---------| 119| --------------- | --------- | ------- | ----------- | ------- |
121| 1 | 8 | 25 | 33 | 76% | 120| 1 | 8 | 25 | 33 | 76% |
122| 2 | 5 | 20 | 25 | 80% | 121| 2 | 5 | 20 | 25 | 80% |
123| 3 | 6 | 12 | 18 | 67% | 122| 3 | 6 | 12 | 18 | 67% |
@@ -136,11 +135,11 @@ total.
136While some practice sessions were worse and some were better, the final results 135While some practice sessions were worse and some were better, the final results
137were similar to my practice exam results. As you can see below, my averages were 136were similar to my practice exam results. As you can see below, my averages were
138slightly worse than my practice exam. However, I got in over 700 questions of 137slightly worse than my practice exam. However, I got in over 700 questions of
139practice and, most importantly, *I read through the explanations every time I 138practice and, most importantly, _I read through the explanations every time I
140answered incorrectly and learned from my mistakes*. 139answered incorrectly and learned from my mistakes_.
141 140
142| Exam Section | Incorrect | Correct | Grand Total | Percent | 141| Exam Section | Incorrect | Correct | Grand Total | Percent |
143|-----------------|-----------|---------|-------------|---------| 142| --------------- | --------- | ------- | ----------- | ------- |
144| 1 | 33 | 108 | 141 | 77% | 143| 1 | 33 | 108 | 141 | 77% |
145| 2 | 33 | 109 | 142 | 77% | 144| 2 | 33 | 109 | 142 | 77% |
146| 3 | 55 | 89 | 144 | 62% | 145| 3 | 55 | 89 | 144 | 62% |
@@ -157,7 +156,7 @@ Now, how do the practice scores reflect my actual results? After all, it's hard
157to tell how good a practice regimen is unless you see how it turns out. 156to tell how good a practice regimen is unless you see how it turns out.
158 157
159| Exam Section | Section Name | Score | 158| Exam Section | Section Name | Score |
160|--------------|------------------------------------------------------------------|-------| 159| ------------ | ---------------------------------------------------------------- | ----- |
161| 1 | Information Systems Auditing Process | 678 | 160| 1 | Information Systems Auditing Process | 678 |
162| 2 | Governance and Management of IT | 590 | 161| 2 | Governance and Management of IT | 590 |
163| 3 | Information Systems Acquisition, Development, and Implementation | 721 | 162| 3 | Information Systems Acquisition, Development, and Implementation | 721 |
@@ -166,7 +165,7 @@ to tell how good a practice regimen is unless you see how it turns out.
166 165
167Now, in order to pass the CISA, you need at least 450 on a sliding scale of 166Now, in order to pass the CISA, you need at least 450 on a sliding scale of
168200-800. Personally, I really have no clue what an average CISA score is. After 167200-800. Personally, I really have no clue what an average CISA score is. After
169a *very* brief look online, I can see that the high end is usually in the low 168a _very_ brief look online, I can see that the high end is usually in the low
170700s. In addition, only about 50-60% of people pass the exam. 169700s. In addition, only about 50-60% of people pass the exam.
171 170
172Given this information, I feel great about my scores. 616 may not be phenomenal, 171Given this information, I feel great about my scores. 616 may not be phenomenal,
content/blog/2022-02-10-leaving-the-office.md +5 −5
@@ -61,9 +61,9 @@ desk feature (I'm over 6 feet tall, so probably not an issue for most people).
61 61
62I loved this environment, it allowed me to focus on my work with minimal 62I loved this environment, it allowed me to focus on my work with minimal
63distractions, but also allowed easy access, so I could spin around in my chair 63distractions, but also allowed easy access, so I could spin around in my chair
64and chat with my friends without leaving my chair. This is the closest I've 64and chat with my friends without leaving my chair. This is the closest I've been
65been to a home office environment (which is my personal favorite, as I'll get 65to a home office environment (which is my personal favorite, as I'll get to
66to later in this post). 66later in this post).
67 67
68## Semi-Open Floor Concept 68## Semi-Open Floor Concept
69 69
@@ -108,8 +108,8 @@ pairs of desk rows are repeated through the office.
108This means that when I go, I need to rent a random desk or try to remember the 108This means that when I go, I need to rent a random desk or try to remember the
109unique ID numbers on desks I like. Once I rent it, I have to make sure no one 109unique ID numbers on desks I like. Once I rent it, I have to make sure no one
110sat down in that desk without renting it. Then, I can sit down and work, but 110sat down in that desk without renting it. Then, I can sit down and work, but
111will probably need to adjust the monitors so that I'm not staring in the face 111will probably need to adjust the monitors so that I'm not staring in the face of
112of the person across from me all day. Finally, I need to wear headphones as this 112the person across from me all day. Finally, I need to wear headphones as this
113environment does nothing to provide you with peace or quiet. 113environment does nothing to provide you with peace or quiet.
114 114
115Luckily, you can rent offices with doors that offer quiet and privacy, which can 115Luckily, you can rent offices with doors that offer quiet and privacy, which can
content/blog/2022-02-10-njalla-dns-api.md +12 −10
@@ -46,7 +46,7 @@ For this demo, we are using the `list-records` and `edit-record` requests.
46The `list-records` request requires the following payload to be sent when 46The `list-records` request requires the following payload to be sent when
47calling the API: 47calling the API:
48 48
49``` txt 49```txt
50params: { 50params: {
51 domain: string 51 domain: string
52} 52}
@@ -55,7 +55,7 @@ params: {
55The `edit-record` request requires the following payload to be sent when calling 55The `edit-record` request requires the following payload to be sent when calling
56the API: 56the API:
57 57
58``` txt 58```txt
59params: { 59params: {
60 domain: string 60 domain: string
61 id: int 61 id: int
@@ -84,19 +84,21 @@ Next, create a Python script file:
84nano ~/ddns/ddns.py 84nano ~/ddns/ddns.py
85``` 85```
86 86
87The following code snippet is quite long, so I won't go into depth on each 87The following code snippet is quite long, so I won't go into depth on each part.
88part. However, I suggest you read through the entire script before running it; 88However, I suggest you read through the entire script before running it; it is
89it is quite simple and contains comments to help explain each code block. 89quite simple and contains comments to help explain each code block.
90 90
91:warning: **Note**: You will need to update the following variables for this to 91:warning: **Note**: You will need to update the following variables for this to
92work: 92work:
93 93
94- `token`: This is the Njalla API token you created earlier. 94- `token`: This is the Njalla API token you created earlier.
95- `user_domain`: This is the top-level domain you want to modify. 95- `user_domain`: This is the top-level domain you want to modify.
96- `include_subdomains`: Set this to `True` if you also want to modify subdomains found under the TLD. 96- `include_subdomains`: Set this to `True` if you also want to modify
97- `subdomains`: If `include_subdomains` = `True`, you can include your list of subdomains to be modified here. 97 subdomains found under the TLD.
98- `subdomains`: If `include_subdomains` = `True`, you can include your list of
99 subdomains to be modified here.
98 100
99``` python 101```python
100#!/usr/bin/python 102#!/usr/bin/python
101# -*- coding: utf-8 -*- 103# -*- coding: utf-8 -*-
102# Import Python modules 104# Import Python modules
content/blog/2022-02-16-debian-and-nginx.md +3 −3
@@ -10,9 +10,9 @@ draft = false
10![Debian + 10![Debian +
11neofetch](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/neofetch.png) 11neofetch](https://img.cleberg.net/blog/20220216-migrating-to-debian-and-nginx/neofetch.png)
12 12
13I've used various Linux distributions throughout the years, but I've never 13I've used various Linux distributions throughout the years, but I've never used
14used anything except Ubuntu for my servers. Why? I really have no idea, mostly 14anything except Ubuntu for my servers. Why? I really have no idea, mostly just
15just comfort around the commands and software availability. 15comfort around the commands and software availability.
16 16
17However, I have always wanted to try Debian as a server OS after testing it out 17However, I have always wanted to try Debian as a server OS after testing it out
18in a VM a few years ago (side-note: I'd love to try Alpine too, but I always 18in a VM a few years ago (side-note: I'd love to try Alpine too, but I always
content/blog/2022-02-17-exiftool.md +10 −10
@@ -16,16 +16,16 @@ There are various components of image metadata that you may want to delete
16before releasing a photo to the public. Here's an incomplete list of things I 16before releasing a photo to the public. Here's an incomplete list of things I
17could easily see just by inspecting a photo on my laptop: 17could easily see just by inspecting a photo on my laptop:
18 18
19- Location (Latitude & Longitude) 19- Location (Latitude & Longitude)
20- Dimensions 20- Dimensions
21- Device Make & Model 21- Device Make & Model
22- Color Space 22- Color Space
23- Color Profile 23- Color Profile
24- Focal Length 24- Focal Length
25- Alpha Channel 25- Alpha Channel
26- Red Eye 26- Red Eye
27- Metering Mode 27- Metering Mode
28- F Number 28- F Number
29 29
30Regardless of your reasoning, I'm going to explain how I used the `exiftool` 30Regardless of your reasoning, I'm going to explain how I used the `exiftool`
31package in Linux to automatically strip metadata from all images in a directory 31package in Linux to automatically strip metadata from all images in a directory
content/blog/2022-02-20-nginx-caching.md +5 −5
@@ -17,7 +17,7 @@ to cache and determining the expiration length. To include more file types,
17simply use the bar separator (`|`) and type the new file extension you want to 17simply use the bar separator (`|`) and type the new file extension you want to
18include. 18include.
19 19
20``` config 20```config
21server { 21server {
22 ... 22 ...
23 23
@@ -35,9 +35,9 @@ changes (i.e., I'm never content with my website), I need to know that my
35readers are seeing the new content without waiting too long. 35readers are seeing the new content without waiting too long.
36 36
37So, I went ahead and set the expiration date at `30d`, which is short enough to 37So, I went ahead and set the expiration date at `30d`, which is short enough to
38refresh for readers but long enough that clients/browsers won't be 38refresh for readers but long enough that clients/browsers won't be re-requesting
39re-requesting the static files too often, hopefully resulting in faster loading 39the static files too often, hopefully resulting in faster loading times, as
40times, as images should be the only thing slowing down my site. 40images should be the only thing slowing down my site.
41 41
42# Testing Results 42# Testing Results
43 43
@@ -48,7 +48,7 @@ recent image from my blog.
48 48
49In the image below, you can see that the `Cache-Control` header is now present 49In the image below, you can see that the `Cache-Control` header is now present
50and set to 2592000, which is 30 days represented in seconds (30 days \_ 24 50and set to 2592000, which is 30 days represented in seconds (30 days \_ 24
51hours/day \_ 60 minutes/hour ** 60 seconds/minute = 2,592,000 seconds). 51hours/day \_ 60 minutes/hour \*\* 60 seconds/minute = 2,592,000 seconds).
52 52
53The `Expires` field is now showing 22 March 2022, which is 30 days from the day 53The `Expires` field is now showing 22 March 2022, which is 30 days from the day
54of this post, 20 February 2022. 54of this post, 20 February 2022.
content/blog/2022-03-02-reliable-notes.md +2 −2
@@ -96,8 +96,8 @@ Here's an example of how my Markdown notes look when opened in plain-text mode:
96![Obsidian Markdown Source 96![Obsidian Markdown Source
97Mode](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.png) 97Mode](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_source_mode.png)
98 98
99Here's the "live preview" version, where the Markdown is rendered into its 99Here's the "live preview" version, where the Markdown is rendered into its HTML
100HTML format: 100format:
101 101
102![Obsidian Markdown Live 102![Obsidian Markdown Live
103Preview](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.png) 103Preview](https://img.cleberg.net/blog/20220302-easy-reliable-note-taking/obsidian_live_preview.png)
content/blog/2022-03-03-financial-database.md +24 −26
@@ -62,7 +62,7 @@ The Accounts table contains summary information about an account, such as a car
62loan or a credit card. By viewing this table, you can find high-level data, such 62loan or a credit card. By viewing this table, you can find high-level data, such
63as interest rate, credit line, or owner. 63as interest rate, credit line, or owner.
64 64
65``` sql 65```sql
66CREATE TABLE "Accounts" ( 66CREATE TABLE "Accounts" (
67 "AccountID" INTEGER NOT NULL UNIQUE, 67 "AccountID" INTEGER NOT NULL UNIQUE,
68 "AccountType" TEXT, 68 "AccountType" TEXT,
@@ -83,7 +83,7 @@ meaning you can join the tables to find a monthly statement for any of the
83accounts listed in the Accounts table. Each statement has an account ID, 83accounts listed in the Accounts table. Each statement has an account ID,
84statement date, and total balance. 84statement date, and total balance.
85 85
86``` sql 86```sql
87CREATE TABLE "Statements" ( 87CREATE TABLE "Statements" (
88 "StatementID" INTEGER NOT NULL UNIQUE, 88 "StatementID" INTEGER NOT NULL UNIQUE,
89 "AccountID" INTEGER, 89 "AccountID" INTEGER,
@@ -101,7 +101,7 @@ tables. This table contains all information you would find on a pay statement
101from an employer. As you change employers or obtain new perks/benefits, just add 101from an employer. As you change employers or obtain new perks/benefits, just add
102new columns to adapt to the new data. 102new columns to adapt to the new data.
103 103
104``` sql 104```sql
105CREATE TABLE "Payroll" ( 105CREATE TABLE "Payroll" (
106 "PaycheckID" INTEGER NOT NULL UNIQUE, 106 "PaycheckID" INTEGER NOT NULL UNIQUE,
107 "PayDate" TEXT, 107 "PayDate" TEXT,
@@ -141,13 +141,13 @@ was to create a process to report and visualize on various aspects of the data.
141In order to explore and create the reports I'm interested in, I utilized a 141In order to explore and create the reports I'm interested in, I utilized a
142two-part process involving Jupyter Notebooks and Python scripts. 142two-part process involving Jupyter Notebooks and Python scripts.
143 143
144### Step 1: Jupyter Notebooks 144### Step 1: Jupyter Notebooks
145 145
146When I need to explore data, try different things, and re-run my code 146When I need to explore data, try different things, and re-run my code
147cell-by-cell, I use Jupyter Notebooks. For example, I explored the 147cell-by-cell, I use Jupyter Notebooks. For example, I explored the `Accounts`
148`Accounts` table until I found the following useful information: 148table until I found the following useful information:
149 149
150``` python 150```python
151import sqlite3 151import sqlite3
152import pandas as pd 152import pandas as pd
153import matplotlib 153import matplotlib
@@ -169,12 +169,12 @@ matplotlib.rcParams['legend.labelcolor'] = 'black'
169df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%') 169df.groupby(['AccountType']).sum().plot.pie(title='Credit Line by Account Type', y='CreditLine', figsize=(5,5), autopct='%1.1f%%')
170``` 170```
171 171
172### Step 2: Python Scripts 172### Step 2: Python Scripts
173 173
174Once I explored enough through the notebooks and had a list of reports I 174Once I explored enough through the notebooks and had a list of reports I wanted,
175wanted, I moved on to create a Python project with the following structure: 175I moved on to create a Python project with the following structure:
176 176
177``` txt 177```txt
178finance/ 178finance/
179├── notebooks/ 179├── notebooks/
180│ │ ├── account_summary.ipynb 180│ │ ├── account_summary.ipynb
@@ -199,16 +199,15 @@ This structure allows me to:
199 installation if I move to a new machine. 199 installation if I move to a new machine.
2002. Activate a virtual environment in `venv/` so I don't need to maintain a 2002. Activate a virtual environment in `venv/` so I don't need to maintain a
201 system-wide Python environment just for this project. 201 system-wide Python environment just for this project.
2023. Keep my `notebooks/` folder to continuously explore the data as I see 2023. Keep my `notebooks/` folder to continuously explore the data as I see fit.
203 fit.
2044. Maintain a local copy of the database in `src/` for easy access. 2034. Maintain a local copy of the database in `src/` for easy access.
2055. Export reports, images, HTML files, etc. to `public/`. 2045. Export reports, images, HTML files, etc. to `public/`.
206 205
207Now, onto the differences between the code in a Jupyter Notebook and the 206Now, onto the differences between the code in a Jupyter Notebook and the actual
208actual Python files. To create the report in the Notebook snippet above, I 207Python files. To create the report in the Notebook snippet above, I created the
209created the following function inside `process.py`: 208following function inside `process.py`:
210 209
211``` python 210```python
212# Create summary pie chart 211# Create summary pie chart
213def summary_data(accounts: pandas.DataFrame) -> None: 212def summary_data(accounts: pandas.DataFrame) -> None:
214 accounts_01 = accounts[accounts["Owner"] == "Person01"] 213 accounts_01 = accounts[accounts["Owner"] == "Person01"]
@@ -244,13 +243,12 @@ Chart](https://img.cleberg.net/blog/20220303-maintaining-a-personal-financial-da
244 243
245Other charts generated by this project include: 244Other charts generated by this project include:
246 245
247- Charts of account balances over time. 246- Charts of account balances over time.
248- Line chart of effective tax rate (taxes divided by taxable income). 247- Line chart of effective tax rate (taxes divided by taxable income).
249- Salary projections and error limits using past income and inflation 248- Salary projections and error limits using past income and inflation rates.
250 rates. 249- Multi-line chart of gross income, taxable income, and net income.
251- Multi-line chart of gross income, taxable income, and net income.
252 250
253The best thing about this project? I can improve it at any given time, 251The best thing about this project? I can improve it at any given time, shaping
254shaping it into whatever helps me the most for that time. I imagine that I 252it into whatever helps me the most for that time. I imagine that I will be
255will be introducing an asset tracking table soon to track the depreciating 253introducing an asset tracking table soon to track the depreciating value of
256value of cars, houses, etc. Who knows what's next? 254cars, houses, etc. Who knows what's next?
content/blog/2022-03-08-plex-migration.md +11 −11
@@ -52,9 +52,9 @@ with the device - it's a good idea to take a photo of this screen, so you can
52enter these commands on the next screen (along with adding support for Nvidia). 52enter these commands on the next screen (along with adding support for Nvidia).
53 53
54Finally, type `Ctrl + C` to enter the command line. From this command line, 54Finally, type `Ctrl + C` to enter the command line. From this command line,
55enter the commands found on the `e` screen. *Remember to add `nomodeset` to the 55enter the commands found on the `e` screen. _Remember to add `nomodeset` to the
56`linux ...` line so that your Nvidia device will display the installation 56`linux ...` line so that your Nvidia device will display the installation
57screens properly!* 57screens properly!_
58 58
59Here's an example of the commands I pulled from the `e` screen and entered on 59Here's an example of the commands I pulled from the `e` screen and entered on
60the command line. 60the command line.
@@ -101,7 +101,7 @@ source/destination.
101 101
102## Step 01: [Client] Update Settings 102## Step 01: [Client] Update Settings
103 103
104Open up a Plex app and *disable* the `Account` > `Library` > `Empty trash 104Open up a Plex app and _disable_ the `Account` > `Library` > `Empty trash
105automatically after every scan` preference for the source server. 105automatically after every scan` preference for the source server.
106 106
107## Step 02: [Destination] Install Plex 107## Step 02: [Destination] Install Plex
@@ -133,8 +133,8 @@ Server data directory
133located?](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/). 133located?](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/).
134 134
135There are many ways to copy the data to the new server and will largely depend 135There are many ways to copy the data to the new server and will largely depend
136on the size of the folder being copied. Personally, my data folder was ~23GB 136on the size of the folder being copied. Personally, my data folder was ~23GB and
137and I opted to simply use the `scp` command to copy the files over SSH. 137I opted to simply use the `scp` command to copy the files over SSH.
138 138
139This process was throttled by the old server's slow HDD and ports and took 139This process was throttled by the old server's slow HDD and ports and took
140approximately 90 minutes to complete. In comparison, moving the data from the 140approximately 90 minutes to complete. In comparison, moving the data from the
@@ -179,12 +179,12 @@ drives from the source server to the destination server.
179Next, perform the following actions in the client: 179Next, perform the following actions in the client:
180 180
1811. On the left sidebar, click `More` > Three-Dot Menu > `Scan Library Files` 1811. On the left sidebar, click `More` > Three-Dot Menu > `Scan Library Files`
1822. *Enable* the `Account` > `Library` > `Empty trash automatically after every 1822. _Enable_ the `Account` > `Library` > `Empty trash automatically after every
183 scan` preference for the source server. 183scan` preference for the source server.
1843. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` > 1843. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` > `Empty
185 `Empty Trash` 185 Trash`
1864. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` > 1864. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` > `Clean
187 `Clean Bundles` 187 Bundles`
1885. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` > 1885. On the left sidebar, click `More` > Three-Dot Menu > `Manage Server` >
189 `Optimize Database` 189 `Optimize Database`
190 190
content/blog/2022-03-23-nextcloud-on-ubuntu.md +4 −4
@@ -34,7 +34,7 @@ sudo mysql -uroot -p
34Once you've logged in, you must create a new user so that Nextcloud can manage 34Once you've logged in, you must create a new user so that Nextcloud can manage
35the database. You will also create a `nextcloud` database and assign privileges: 35the database. You will also create a `nextcloud` database and assign privileges:
36 36
37``` sql 37```sql
38CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; 38CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
39CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 39CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
40GRANT ALL PRIVILEGES ON nextcloud.** TO 'username'@'localhost'; 40GRANT ALL PRIVILEGES ON nextcloud.** TO 'username'@'localhost';
@@ -74,7 +74,7 @@ sudo nano /etc/apache2/sites-available/nextcloud.conf
74Once the editor is open, paste the following information in. Then, save and 74Once the editor is open, paste the following information in. Then, save and
75close the file. 75close the file.
76 76
77``` config 77```config
78<VirtualHost *:80> 78<VirtualHost *:80>
79 DocumentRoot /var/www/example.com 79 DocumentRoot /var/www/example.com
80 ServerName example.com 80 ServerName example.com
@@ -154,9 +154,9 @@ of Nextcloud, using the `Breeze Dark` theme I installed from the Apps page.
154![Nextcloud 154![Nextcloud
155Dashboard](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_dashboard.png) 155Dashboard](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_dashboard.png)
156 156
157*Figure 01: Nextcloud Dashboard* 157_Figure 01: Nextcloud Dashboard_
158 158
159![Nextcloud 159![Nextcloud
160Settings](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_settings.png) 160Settings](https://img.cleberg.net/blog/20220323-installing-nextcloud-on-ubuntu/nextcloud_settings.png)
161 161
162*Figure 02: Nextcloud Security Settings* 162_Figure 02: Nextcloud Security Settings_
content/blog/2022-03-24-server-hardening.md +64 −63
@@ -16,7 +16,7 @@ draft = false
16 16
17## My Personal Data Flow 17## My Personal Data Flow
18 18
19``` txt 19```txt
20 ┌───────┐ ┌─────────────────┐ 20 ┌───────┐ ┌─────────────────┐
21 ┌──► VLAN1 ├───► Private Devices │ 21 ┌──► VLAN1 ├───► Private Devices │
22 │ └───────┘ └─────────────────┘ 22 │ └───────┘ └─────────────────┘
@@ -35,44 +35,44 @@ have to think about the transport of data from `server` to `client`.
35 35
36Let's start with the actual server itself. Think about the following: 36Let's start with the actual server itself. Think about the following:
37 37
38- Do I have a firewall enabled? Do I need to update this to allow new ports or 38- Do I have a firewall enabled? Do I need to update this to allow new ports or
39 IPs? 39 IPs?
40- Do I have an IPS/IDS that may prevent outside traffic? 40- Do I have an IPS/IDS that may prevent outside traffic?
41- Do I have any other security software installed? 41- Do I have any other security software installed?
42- Are the services hosted inside Docker containers, behind a reverse proxy, or 42- Are the services hosted inside Docker containers, behind a reverse proxy, or
43 virtualized? If so, are they configured to allow outside traffic? 43 virtualized? If so, are they configured to allow outside traffic?
44 44
45Once the data leaves the server, where does it go? In my case, it goes to a 45Once the data leaves the server, where does it go? In my case, it goes to a
46managed switch. In this case, I asked the following: 46managed switch. In this case, I asked the following:
47 47
48- What configurations is the switch using? 48- What configurations is the switch using?
49- Am I using VLANs? 49- Am I using VLANs?
50 - Yes, I am using 802.1Q VLANs. 50 - Yes, I am using 802.1Q VLANs.
51- Are the VLANs configured properly? 51- Are the VLANs configured properly?
52 - Yes, as shown in the Switch section below, I have a separate VLAN to allow 52 - Yes, as shown in the Switch section below, I have a separate VLAN to
53 outside traffic to and from the server alone. No other devices, except for 53 allow outside traffic to and from the server alone. No other devices,
54 a service port, and in that VLAN. 54 except for a service port, and in that VLAN.
55 55
56At this point, the data has been processed through the switch. Where does it go 56At this point, the data has been processed through the switch. Where does it go
57next? In my case, it's pretty simple: it goes to the router/modem device. 57next? In my case, it's pretty simple: it goes to the router/modem device.
58 58
59- Does my ISP block any ports that I need? 59- Does my ISP block any ports that I need?
60 - This is an important step that a lot of people run into when self-hosting 60 - This is an important step that a lot of people run into when
61 at home. Use an online port-checker tool for your IP or call your ISP if 61 self-hosting at home. Use an online port-checker tool for your IP or
62 you think ports are blocked. 62 call your ISP if you think ports are blocked.
63- Is there a router firewall? 63- Is there a router firewall?
64 - Yes, I checked that it's configured to allow the ports I need to run my 64 - Yes, I checked that it's configured to allow the ports I need to run my
65 services publicly. Common web servers and reverse proxies require ports 80 65 services publicly. Common web servers and reverse proxies require ports
66 and 443, but other services like media servers or games can require unique 66 80 and 443, but other services like media servers or games can require
67 ports, so be sure to check the documentation for your service(s). 67 unique ports, so be sure to check the documentation for your service(s).
68- Are there any other settings affecting inbound/outbound traffic? 68- Are there any other settings affecting inbound/outbound traffic?
69 - Schedules or access blocks 69 - Schedules or access blocks
70 - Static Routing 70 - Static Routing
71 - QoS 71 - QoS
72 - Port Forwarding 72 - Port Forwarding
73 - DMZ Hosting 73 - DMZ Hosting
74 - Remote Management (this can sometimes mess with services that also require 74 - Remote Management (this can sometimes mess with services that also
75 the use of ports 80 and 443) 75 require the use of ports 80 and 443)
76 76
77Once the data leaves my router, it goes to the upstream ISP and can be accessed 77Once the data leaves my router, it goes to the upstream ISP and can be accessed
78publicly. 78publicly.
@@ -172,7 +172,7 @@ sudo ufw enable
172 rules is commented-out or doesn't exist, create the rule at the bottom of 172 rules is commented-out or doesn't exist, create the rule at the bottom of
173 the file. 173 the file.
174 174
175 ``` config 175 ```config
176 PermitRootLogin no 176 PermitRootLogin no
177 PasswordAuthentication no 177 PasswordAuthentication no
178 PubkeyAuthentication yes 178 PubkeyAuthentication yes
@@ -192,10 +192,10 @@ sudo ufw enable
192 192
1933. Enable MFA for `ssh` 1933. Enable MFA for `ssh`
194 194
195 This part is optional, but I highly recommend it. So far, we've ensured 195 This part is optional, but I highly recommend it. So far, we've ensured that
196 that no one can log into our user on the server without using our secret 196 no one can log into our user on the server without using our secret key, and
197 key, and we've ensured that no one can log in remotely as `root`. Next, you 197 we've ensured that no one can log in remotely as `root`. Next, you can
198 can enable MFA authentication for `ssh` connections. 198 enable MFA authentication for `ssh` connections.
199 199
200 This process involves editing a couple files and installing an MFA package, 200 This process involves editing a couple files and installing an MFA package,
201 so I will not include all the details in this post. To see how to configure 201 so I will not include all the details in this post. To see how to configure
@@ -203,7 +203,7 @@ sudo ufw enable
203 SSH](../enable-totp-mfa-for-ssh/). 203 SSH](../enable-totp-mfa-for-ssh/).
204 204
205 ![SSH 205 ![SSH
206 MFA](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/ssh_mfa.png) 206MFA](https://img.cleberg.net/blog/20220324-hardening-a-public-facing-home-server/ssh_mfa.png)
207 207
208## `fail2ban` 208## `fail2ban`
209 209
@@ -239,10 +239,10 @@ order to SSH to this server, I need to plug my laptop into port 23 or else I
239cannot SSH. Otherwise, I'd need to hook up a monitor and keyboard directly to 239cannot SSH. Otherwise, I'd need to hook up a monitor and keyboard directly to
240the server to manage it. 240the server to manage it.
241 241
242| 242|
243 243
244| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports | 244| VLAN ID | VLAN Name | Member Ports | Tagged Ports | Untagged Ports |
245|---------|-----------|--------------|--------------|----------------| 245| ------- | --------- | ------------ | ------------ | -------------- |
246| 1 | Default | 1-24 | 1-24 | | 246| 1 | Default | 1-24 | 1-24 | |
247| 2 | Server | 1,8,23 | 1,8,23 | | 247| 2 | Server | 1,8,23 | 1,8,23 | |
248 248
@@ -253,7 +253,7 @@ any related ports (in this case, see that ports `8` and `23` have a PVID of
253`2`). 253`2`).
254 254
255| Port | PVID | 255| Port | PVID |
256|------|------| 256| ---- | ---- |
257| 1 | 1 | 257| 1 | 1 |
258| 2 | 1 | 258| 2 | 1 |
259| 3 | 1 | 259| 3 | 1 |
@@ -285,9 +285,9 @@ On my router, the configuration was as easy as opening the firewall settings and
285unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL, 285unblocking the ports I needed for my services (e.g., HTTP/S, Plex, SSH, MySQL,
286etc.). 286etc.).
287 287
288*Since I'm relying on an ISP-provided modem/router combo for now (not by 288_Since I'm relying on an ISP-provided modem/router combo for now (not by
289choice), I do not use any other advanced settings on my router that would 289choice), I do not use any other advanced settings on my router that would
290inhibit any valid traffic to these services.* 290inhibit any valid traffic to these services._
291 291
292The paragraph above regarding the ISP-owned router is no longer accurate as I 292The paragraph above regarding the ISP-owned router is no longer accurate as I
293now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I 293now use the Ubiquiti Unifi Dream Machine Pro as my router. Within this router, I
@@ -303,7 +303,7 @@ available to you.
303 303
304One large piece of self-hosting that people generally don't discuss online is 304One large piece of self-hosting that people generally don't discuss online is
305physical security. However, physical security is very important for everyone who 305physical security. However, physical security is very important for everyone who
306hosts a server like this. Exactly *how* important it is depends on the server 306hosts a server like this. Exactly _how_ important it is depends on the server
307use/purpose. 307use/purpose.
308 308
309If you self-host customer applications that hold protected data (HIPAA, GDPR, 309If you self-host customer applications that hold protected data (HIPAA, GDPR,
@@ -315,24 +315,25 @@ minor consideration, but one you still need to think about.
315 315
316The first consideration is quite simple: location. 316The first consideration is quite simple: location.
317 317
318- Is the server within a property you own or housed on someone else's property? 318- Is the server within a property you own or housed on someone else's
319- Is it nearby (in your house, in your work office, in your neighbor's garage, 319 property?
320 in a storage unit, etc.)? 320- Is it nearby (in your house, in your work office, in your neighbor's garage,
321- Do you have 24/7 access to the server? 321 in a storage unit, etc.)?
322- Are there climate considerations, such as humidity, fires, tornadoes, 322- Do you have 24/7 access to the server?
323 monsoons? 323- Are there climate considerations, such as humidity, fires, tornadoes,
324- Do you have emergency equipment nearby in case of emergency? 324 monsoons?
325- Do you have emergency equipment nearby in case of emergency?
325 326
326## Hardware Ownership 327## Hardware Ownership
327 328
328Secondly, consider the hardware itself: 329Secondly, consider the hardware itself:
329 330
330- Do you own the server in its entirety? 331- Do you own the server in its entirety?
331- Are any other users able to access the server, even if your data/space is 332- Are any other users able to access the server, even if your data/space is
332 segregated? 333 segregated?
333- If you're utilizing a third party, do they have any documentation to show 334- If you're utilizing a third party, do they have any documentation to show
334 responsibility? This could be a SOC 1/2/3 report, ISO compliance report, 335 responsibility? This could be a SOC 1/2/3 report, ISO compliance report,
335 internal security/safety documentation. 336 internal security/safety documentation.
336 337
337## Physical Controls 338## Physical Controls
338 339
@@ -342,10 +343,10 @@ usually covered already if you're utilizing a third party.
342 343
343These can include: 344These can include:
344 345
345- Server bezel locks 346- Server bezel locks
346- Server room locks - physical, digital, or biometric authentication 347- Server room locks - physical, digital, or biometric authentication
347- Security cameras 348- Security cameras
348- Raised floors/lowered ceilings with proper guards/gates in-place within the 349- Raised floors/lowered ceilings with proper guards/gates in-place within the
349 floors or ceilings 350 floors or ceilings
350- Security personnel 351- Security personnel
351- Log sheets and/or guest badges 352- Log sheets and/or guest badges
content/blog/2022-03-26-ssh-mfa.md +13 −13
@@ -11,10 +11,10 @@ If you are a sysadmin of a server anywhere (that includes at home!), you may
11want an added layer of protection against intruders. This is not a replacement 11want an added layer of protection against intruders. This is not a replacement
12for other security measures, such as: 12for other security measures, such as:
13 13
14- Disable root SSH 14- Disable root SSH
15- Disable SSH password authentication 15- Disable SSH password authentication
16- Allow only certain users to login via SSH 16- Allow only certain users to login via SSH
17- Allow SSH only from certain IPs 17- Allow SSH only from certain IPs
18 18
19However, MFA can be added as an additional security measure to ensure that your 19However, MFA can be added as an additional security measure to ensure that your
20server is protected. This is especially important if you need to allow password 20server is protected. This is especially important if you need to allow password
@@ -52,7 +52,7 @@ If you are not sure how to answer, read the prompts carefully and think about
52having to how each situation would affect your normal login attempts. If you are 52having to how each situation would affect your normal login attempts. If you are
53still not sure, use my default responses below. 53still not sure, use my default responses below.
54 54
55``` txt 55```txt
56OUTPUT 56OUTPUT
57 57
58Do you want authentication tokens to be time-based (y/n) y 58Do you want authentication tokens to be time-based (y/n) y
@@ -62,13 +62,13 @@ At this point, use an authenticator app somewhere one of your devices to scan
62the QR code. Any future login attempts after our upcoming configuration changes 62the QR code. Any future login attempts after our upcoming configuration changes
63will require that TOTP. 63will require that TOTP.
64 64
65``` txt 65```txt
66OUTPUT 66OUTPUT
67 67
68Do you want me to update your "/home/user/.google_authenticator" file? (y/n) y 68Do you want me to update your "/home/user/.google_authenticator" file? (y/n) y
69``` 69```
70 70
71``` txt 71```txt
72OUTPUT 72OUTPUT
73 73
74Do you want to disallow multiple uses of the same authentication 74Do you want to disallow multiple uses of the same authentication
@@ -76,7 +76,7 @@ token? This restricts you to one login about every 30s, but it increases
76your chances to notice or even prevent man-in-the-middle attacks (y/n) y 76your chances to notice or even prevent man-in-the-middle attacks (y/n) y
77``` 77```
78 78
79``` txt 79```txt
80OUTPUT 80OUTPUT
81 81
82By default, a new token is generated every 30 seconds by the mobile app. 82By default, a new token is generated every 30 seconds by the mobile app.
@@ -91,7 +91,7 @@ between client and server.
91Do you want to do so? (y/n) n 91Do you want to do so? (y/n) n
92``` 92```
93 93
94``` txt 94```txt
95OUTPUT 95OUTPUT
96 96
97If the computer that you are logging into isn't hardened against brute-force 97If the computer that you are logging into isn't hardened against brute-force
@@ -112,7 +112,7 @@ google-authenticator -t -d -f -r 3 -R 30 -w 3
112 112
113The options referenced above are as follows: 113The options referenced above are as follows:
114 114
115``` txt 115```txt
116google-authenticator [<options>] 116google-authenticator [<options>]
117 -h, --help Print this message 117 -h, --help Print this message
118 -c, --counter-based Set up counter-based (HOTP) verification 118 -c, --counter-based Set up counter-based (HOTP) verification
@@ -152,7 +152,7 @@ sudo nano /etc/pam.d/sshd
152You need to do two things in this file. First, add the following lines to the 152You need to do two things in this file. First, add the following lines to the
153bottom of the file: 153bottom of the file:
154 154
155``` config 155```config
156auth required pam_google_authenticator.so nullok 156auth required pam_google_authenticator.so nullok
157auth required pam_permit.so 157auth required pam_permit.so
158``` 158```
@@ -166,7 +166,7 @@ following three authentication factors:
1662. Password 1662. Password
1673. T/OTP code 1673. T/OTP code
168 168
169``` config 169```config
170#@include common-auth 170#@include common-auth
171``` 171```
172 172
@@ -181,7 +181,7 @@ sudo nano /etc/ssh/sshd_config
181You'll need to change `ChallengeResponseAuthentication` to yes and add the 181You'll need to change `ChallengeResponseAuthentication` to yes and add the
182`AuthenticationMethods` line to the bottom of the file. 182`AuthenticationMethods` line to the bottom of the file.
183 183
184``` config 184```config
185ChallengeResponseAuthentication yes 185ChallengeResponseAuthentication yes
186AuthenticationMethods publickey,password publickey,keyboard-interactive 186AuthenticationMethods publickey,password publickey,keyboard-interactive
187``` 187```
content/blog/2022-04-02-nginx-reverse-proxy.md +15 −15
@@ -16,13 +16,13 @@ where each request should be sent.
16 16
17For example, let's say that I run three servers in my home: 17For example, let's say that I run three servers in my home:
18 18
19- Server01 (`example.com`) 19- Server01 (`example.com`)
20- Server02 (`service01.example.com`) 20- Server02 (`service01.example.com`)
21- Server03 (`service02.example.com`) 21- Server03 (`service02.example.com`)
22 22
23I also run a reverse proxy in my home that intercepts all public traffic: 23I also run a reverse proxy in my home that intercepts all public traffic:
24 24
25- Reverse Proxy 25- Reverse Proxy
26 26
27Assume that I have a domain name (`example.com`) that allows clients to request 27Assume that I have a domain name (`example.com`) that allows clients to request
28websites or services from my home servers. 28websites or services from my home servers.
@@ -36,7 +36,7 @@ Server~01~ holds that data, Nginx will send the user to Server~01~. If I were to
36change the configuration so that `example.com` is routed to Server~02~, that 36change the configuration so that `example.com` is routed to Server~02~, that
37same user would be sent to Server~02~ instead. 37same user would be sent to Server~02~ instead.
38 38
39``` txt 39```txt
40┌──────┐ ┌───────────┐ 40┌──────┐ ┌───────────┐
41│ User │─┐ ┌──► Server_01 │ 41│ User │─┐ ┌──► Server_01 │
42└──────┘ │ │ └───────────┘ 42└──────┘ │ │ └───────────┘
@@ -54,11 +54,11 @@ There are a lot of options when it comes to reverse proxy servers, so I'm just
54going to list a few of the options I've heard recommended over the last few 54going to list a few of the options I've heard recommended over the last few
55years: 55years:
56 56
57- [Nginx](https://nginx.com) 57- [Nginx](https://nginx.com)
58- [Caddy](https://caddyserver.com) 58- [Caddy](https://caddyserver.com)
59- [Traefik](https://traefik.io/) 59- [Traefik](https://traefik.io/)
60- [HAProxy](https://www.haproxy.org/) 60- [HAProxy](https://www.haproxy.org/)
61- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid) 61- [Squid](https://ubuntu.com/server/docs/proxy-servers-squid)
62 62
63In this post, we will be using Nginx as our reverse proxy, running on Ubuntu 63In this post, we will be using Nginx as our reverse proxy, running on Ubuntu
64Server 20.04.4 LTS. 64Server 20.04.4 LTS.
@@ -118,8 +118,8 @@ search box and ensuring the results are showing the correct IP address.
118## Step 2: Open Network Ports 118## Step 2: Open Network Ports
119 119
120This step will be different depending on which router you have in your home. If 120This step will be different depending on which router you have in your home. If
121you're not sure, try to visit [192.168.1.1](http://192.168.1.1) in your 121you're not sure, try to visit [192.168.1.1](http://192.168.1.1) in your browser.
122browser. Login credentials are usually written on a sticker somewhere on your 122Login credentials are usually written on a sticker somewhere on your
123modem/router. 123modem/router.
124 124
125Once you're able to log in to your router, find the Port Forwarding settings. 125Once you're able to log in to your router, find the Port Forwarding settings.
@@ -131,7 +131,7 @@ this table, `xxx.xxx.xxx.xxx` is the local device IP of the reverse proxy
131server, it will probably be an IP between `192.168.1.1` and `192.168.1.255`. 131server, it will probably be an IP between `192.168.1.1` and `192.168.1.255`.
132 132
133| NAME | FROM PORT | DEST PORT/IP | ENABLED | 133| NAME | FROM PORT | DEST PORT/IP | ENABLED |
134|-------|-----------|-----------------|---------| 134| ----- | --------- | --------------- | ------- |
135| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE | 135| HTTP | 80 | xxx.xxx.xxx.xxx | TRUE |
136| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE | 136| HTTPS | 443 | xxx.xxx.xxx.xxx | TRUE |
137 137
@@ -172,7 +172,7 @@ Dashy:
172nano /etc/nginx/sites-available/dashy.example.com 172nano /etc/nginx/sites-available/dashy.example.com
173``` 173```
174 174
175``` config 175```config
176server { 176server {
177 listen 80; 177 listen 80;
178 server_name dashy.example.com; 178 server_name dashy.example.com;
@@ -189,7 +189,7 @@ Uptime:
189nano /etc/nginx/sites-available/uptime.example.com 189nano /etc/nginx/sites-available/uptime.example.com
190``` 190```
191 191
192``` config 192```config
193server { 193server {
194 listen 80; 194 listen 80;
195 server_name uptime.example.com; 195 server_name uptime.example.com;
content/blog/2022-04-09-pinetime.md +20 −20
@@ -22,20 +22,20 @@ for each watch and the primary functions:
22 22
231. Price: 231. Price:
24 24
25 - $26.99 (Sealed) 25 - $26.99 (Sealed)
26 - $24.99 (Dev Kit) 26 - $24.99 (Dev Kit)
27 - $51.98 (One Sealed + One Dev Kit) 27 - $51.98 (One Sealed + One Dev Kit)
28 28
292. Primary Functionality: 292. Primary Functionality:
30 30
31 - Clock (+ Smartphone Sync) 31 - Clock (+ Smartphone Sync)
32 - Pedometer 32 - Pedometer
33 - Heart Rate Monitor 33 - Heart Rate Monitor
34 - Sleep Monitor 34 - Sleep Monitor
35 - Calories burned 35 - Calories burned
36 - Messaging 36 - Messaging
37 - Smartphone Notifications 37 - Smartphone Notifications
38 - Media Controls 38 - Media Controls
39 39
40# Unboxing 40# Unboxing
41 41
@@ -61,10 +61,10 @@ While turning on the watch for the first time, some of the main design choices
61you can see in the watch OS, 61you can see in the watch OS,
62[InfiniTime](https://wiki.pine64.org/wiki/InfiniTime), are: 62[InfiniTime](https://wiki.pine64.org/wiki/InfiniTime), are:
63 63
64- A square bezel, not too thin against the sides of the watch. 64- A square bezel, not too thin against the sides of the watch.
65- A simple, rubber band. 65- A simple, rubber band.
66- Basic font and screen pixel design. 66- Basic font and screen pixel design.
67- Swipe gestures to access other screens. 67- Swipe gestures to access other screens.
68 68
69![PineTime 69![PineTime
70Screens](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime.png) 70Screens](https://img.cleberg.net/blog/20220409-pinetime-smart-watch/pinetime.png)
@@ -73,7 +73,7 @@ The OS itself is fantastic in terms of functionality for me. It does exactly
73what a smartwatch should do - track time, steps, heart rates, and connect to 73what a smartwatch should do - track time, steps, heart rates, and connect to
74another smart device, without being overly burdensome to the user. 74another smart device, without being overly burdensome to the user.
75 75
76My only gripe so far is that it's *really* difficult to swipe to different 76My only gripe so far is that it's _really_ difficult to swipe to different
77screens, such as pulling down the notification tray. I'm not sure if this is an 77screens, such as pulling down the notification tray. I'm not sure if this is an
78OS or hardware issue, but it makes it quite hard to quickly move around the 78OS or hardware issue, but it makes it quite hard to quickly move around the
79screens. 79screens.
@@ -91,10 +91,10 @@ Since I am using iOS as my primary mobile device OS, I am using the
91 91
92This app provides the following for PineTime owners: 92This app provides the following for PineTime owners:
93 93
94- Firmware updates 94- Firmware updates
95- Steps 95- Steps
96- Charts 96- Charts
97- Notifications 97- Notifications
98 98
99I mashed up a few screenshots to show off the home page, menu, firmware update, 99I mashed up a few screenshots to show off the home page, menu, firmware update,
100and notification test screens: 100and notification test screens:
content/blog/2022-06-01-ditching-cloudflare.md +2 −2
@@ -25,8 +25,8 @@ if they're worth the higher rates (one domain is 30€ and the other is 45€).+
25 25
26> **Update (2022.06.03)**: I ended up transferring my final two domains over to 26> **Update (2022.06.03)**: I ended up transferring my final two domains over to
27> Njalla, clearing my Cloudflare account of personal data, and deleting the 27> Njalla, clearing my Cloudflare account of personal data, and deleting the
28> Cloudflare account entirely. *I actually feel relieved to have moved on to a 28> Cloudflare account entirely. _I actually feel relieved to have moved on to a
29> provider I trust.* 29> provider I trust._
30 30
31# DNS 31# DNS
32 32
content/blog/2022-06-07-self-hosting-freshrss.md +10 −10
@@ -46,7 +46,7 @@ of the server and an `AAAA` record with the IPv6 address of the server. Note:
46assigning an IPv6 (`AAAA`) record is optional, but I like to enable IPV6 for my 46assigning an IPv6 (`AAAA`) record is optional, but I like to enable IPV6 for my
47services. 47services.
48 48
49``` config 49```config
50rss.example.com A xxx.xxx.xxx.xxx 50rss.example.com A xxx.xxx.xxx.xxx
51rss.example.com AAAA xxxx:xxxx: ... :xxxx 51rss.example.com AAAA xxxx:xxxx: ... :xxxx
52``` 52```
@@ -55,8 +55,8 @@ rss.example.com AAAA xxxx:xxxx: ... :xxxx
55 55
56I initially tried to set up a `docker-compose.yml` file with a `.env` file 56I initially tried to set up a `docker-compose.yml` file with a `.env` file
57because I prefer to have a file I can look back at later to see how I initially 57because I prefer to have a file I can look back at later to see how I initially
58started the container, but it simply wouldn't work for me. I'm not sure why, 58started the container, but it simply wouldn't work for me. I'm not sure why, but
59but I assume I wasn't telling `docker-compose` where the `.env` file was. 59I assume I wasn't telling `docker-compose` where the `.env` file was.
60 60
61Regardless, I chose to simply run the service with `docker run`. See the 61Regardless, I chose to simply run the service with `docker run`. See the
62following command for my `docker run` configuration: 62following command for my `docker run` configuration:
@@ -79,8 +79,8 @@ instance at `localhost:8080`.
79 79
80I **HIGHLY** suggest that you set up your user account prior to exposing this 80I **HIGHLY** suggest that you set up your user account prior to exposing this
81service to the public. It's unlikely that someone is trying to access the exact 81service to the public. It's unlikely that someone is trying to access the exact
82domain or IP/port you're assigning here, but as soon as you expose this 82domain or IP/port you're assigning here, but as soon as you expose this service,
83service, the first person to open the URL will be able to create the admin user. 83the first person to open the URL will be able to create the admin user.
84 84
85In order to set up your FreshRSS service, open the `localhost:8080` URL in your 85In order to set up your FreshRSS service, open the `localhost:8080` URL in your
86browser (you may need to use a local IP instead of `localhost` if you're 86browser (you may need to use a local IP instead of `localhost` if you're
@@ -104,7 +104,7 @@ sudo nano /etc/nginx/sites-available/rss.example.com
104 104
105Within the config file, I pasted the following code: 105Within the config file, I pasted the following code:
106 106
107``` config 107```config
108upstream freshrss { 108upstream freshrss {
109 server 127.0.0.1:8080; 109 server 127.0.0.1:8080;
110 keepalive 64; 110 keepalive 64;
@@ -171,7 +171,7 @@ Once that is set and saved, click the link below the API password field to open
171the API check tool. It should look something like `https://localhost:8080/api/` 171the API check tool. It should look something like `https://localhost:8080/api/`
172or `https://rss.example.com/api/`. 172or `https://rss.example.com/api/`.
173 173
174Within this page, you *should* see your correct external URL and "PASS" at the 174Within this page, you _should_ see your correct external URL and "PASS" at the
175bottom of each API type. This would mean everything is set up correctly, and you 175bottom of each API type. This would mean everything is set up correctly, and you
176can now move on and login to any RSS apps that support self-hosted options. 176can now move on and login to any RSS apps that support self-hosted options.
177 177
@@ -205,7 +205,7 @@ Within `config.php`, you will need to update the `base_url` variable and update
205it to match your external URL. In my case, I simply commented-out the incorrect 205it to match your external URL. In my case, I simply commented-out the incorrect
206URL with `//` and added the correct one on a new line: 206URL with `//` and added the correct one on a new line:
207 207
208``` php 208```php
209<?php 209<?php
210 return array ( 210 return array (
211 ... 211 ...
@@ -231,8 +231,8 @@ Next, just restart the container:
231sudo docker restart freshrss 231sudo docker restart freshrss
232``` 232```
233 233
234Voilà! Your API check should now "PASS" and you should be able to use one of 234Voilà! Your API check should now "PASS" and you should be able to use one of the
235the API URLs in your RSS apps. 235API URLs in your RSS apps.
236 236
237In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop and 237In my case, I use [NetNewsWire](https://netnewswire.com) on my desktop and
238phone. 238phone.
content/blog/2022-06-16-terminal-lifestyle.md +22 −23
@@ -7,31 +7,31 @@ draft = false
7 7
8# Text-Based Simplicity 8# Text-Based Simplicity
9 9
10I've detailed my views on web-based minimalism and related topics in other 10I've detailed my views on web-based minimalism and related topics in other posts
11posts throughout the years; e.g., JavaScript/CSS bloat slowing down websites 11throughout the years; e.g., JavaScript/CSS bloat slowing down websites that are
12that are essentially a text document. However, I have never really expanded 12essentially a text document. However, I have never really expanded beyond
13beyond talking about the web and describing how I focus on minimizing 13talking about the web and describing how I focus on minimizing distractions in
14distractions in other digital environments. 14other digital environments.
15 15
16This post is going to set the baseline for how I *try* to live my digital life. 16This post is going to set the baseline for how I _try_ to live my digital life.
17It does not necessarily get into my physical life, which is often harder to 17It does not necessarily get into my physical life, which is often harder to
18control and contain all the noise in our modern world. 18control and contain all the noise in our modern world.
19 19
20While there are new things to do every day in our digital world, I find that 20While there are new things to do every day in our digital world, I find that
21keeping a core set of values and interests can ground you and keep you mindful 21keeping a core set of values and interests can ground you and keep you mindful
22of *why* you are participating in the digital world. For example, if - at your 22of _why_ you are participating in the digital world. For example, if - at your
23core - you have no interest in what strangers think about random topics, it 23core - you have no interest in what strangers think about random topics, it
24would be unwise to start participating in social media. However, I am someone 24would be unwise to start participating in social media. However, I am someone
25who has been dragged in by effective advertising to participate in communities 25who has been dragged in by effective advertising to participate in communities
26that I realize I do not care for. 26that I realize I do not care for.
27 27
28I won't dive much further into explaining the philosophy of all this, but I 28I won't dive much further into explaining the philosophy of all this, but I will
29will link a few helpful articles that may pique your interest if you're in 29link a few helpful articles that may pique your interest if you're in search of
30search of more meaningful experiences: 30more meaningful experiences:
31 31
32- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness) 32- [Mindfulness](https://en.wikipedia.org/wiki/Mindfulness)
33- [Minimalism](https://en.wikipedia.org/wiki/Minimalism) 33- [Minimalism](https://en.wikipedia.org/wiki/Minimalism)
34- [Stoicism](https://en.wikipedia.org/wiki/Stoicism) 34- [Stoicism](https://en.wikipedia.org/wiki/Stoicism)
35 35
36# Living Life in the Terminal 36# Living Life in the Terminal
37 37
@@ -62,9 +62,8 @@ Now that we have some examples out of the way, let's dive into the specifics.
62 62
63I'm going to start off with a hard topic for those who prefer to live in the 63I'm going to start off with a hard topic for those who prefer to live in the
64terminal: web browsing. This task is made hard mostly by websites and web apps 64terminal: web browsing. This task is made hard mostly by websites and web apps
65that require JavaScript to run. The other difficult part is that if you're 65that require JavaScript to run. The other difficult part is that if you're using
66using a text-based browser, that means images won't load (hopefully that's 66a text-based browser, that means images won't load (hopefully that's obvious).
67obvious).
68 67
69I am using [Lynx](https://lynx.invisible-island.net), a text-based browser that 68I am using [Lynx](https://lynx.invisible-island.net), a text-based browser that
70runs quickly and easily in the terminal. Lynx allows me to browser most websites 69runs quickly and easily in the terminal. Lynx allows me to browser most websites
@@ -79,10 +78,10 @@ using their text-only interface.
79![DuckDuckGo 78![DuckDuckGo
80!Lite](https://img.cleberg.net/blog/20220616-terminal-lifestyle/ddg.png) 79!Lite](https://img.cleberg.net/blog/20220616-terminal-lifestyle/ddg.png)
81 80
82Eventually, you will run into websites that don't work (or are just too ugly 81Eventually, you will run into websites that don't work (or are just too ugly and
83and messy) in a text-only mode, and you'll be forced to switch over to a GUI 82messy) in a text-only mode, and you'll be forced to switch over to a GUI browser
84browser to look at that site. Personally, I don't mind this as it doesn't 83to look at that site. Personally, I don't mind this as it doesn't happen as
85happen as often as I thought it would. 84often as I thought it would.
86 85
87The only time I need to do this is when I want to browse an image/video-focused 86The only time I need to do this is when I want to browse an image/video-focused
88webpage or if I need to log in to a site, and it doesn't support a text-only 87webpage or if I need to log in to a site, and it doesn't support a text-only
@@ -94,8 +93,8 @@ login page. For example, I am able to easily log in to
94After web browsing activities, my main form of terminal communication is Matrix. 93After web browsing activities, my main form of terminal communication is Matrix.
95I use the [gomuks](https://docs.mau.fi/gomuks/) client currently. 94I use the [gomuks](https://docs.mau.fi/gomuks/) client currently.
96 95
97This was incredibly easy to install on macOS (but I will need to see if it'll 96This was incredibly easy to install on macOS (but I will need to see if it'll be
98be just as easy on Linux when my new laptop arrives): 97just as easy on Linux when my new laptop arrives):
99 98
100```sh 99```sh
101brew install gomuks 100brew install gomuks
@@ -178,7 +177,7 @@ I am used to the easy extensions found in VSCodium and Kate, so I am slowly
178learning how to mold the default editing tools to my needs. Currently, this 177learning how to mold the default editing tools to my needs. Currently, this
179means I am using `nano` with the following configuration: 178means I am using `nano` with the following configuration:
180 179
181``` config 180```config
182set breaklonglines 181set breaklonglines
183set autoindent 182set autoindent
184set linenumbers 183set linenumbers
content/blog/2022-06-22-daily-poetry.md +46 −46
@@ -7,8 +7,8 @@ draft = false
7 7
8# Source Code 8# Source Code
9 9
10I don't want to bury the lede here, so if you'd like to see the full source 10I don't want to bury the lede here, so if you'd like to see the full source code
11code I use to email myself plaintext poems daily, visit the repository: 11I use to email myself plaintext poems daily, visit the repository:
12[daily-poem.git](https://git.cleberg.net/?p=daily-poem.git;a=summary). 12[daily-poem.git](https://git.cleberg.net/?p=daily-poem.git;a=summary).
13 13
14# My Daily Dose of Poetry 14# My Daily Dose of Poetry
@@ -20,8 +20,8 @@ In this case, I was looking for a simply and easy way to get a daily dose of
20literature or poetry to read in the mornings. 20literature or poetry to read in the mornings.
21 21
22However, I don't want to sign up for a random mailing list on just any website. 22However, I don't want to sign up for a random mailing list on just any website.
23I also don't want to have to work to find the reading content each morning, as 23I also don't want to have to work to find the reading content each morning, as I
24I know I would simply give up and stop reading daily. 24know I would simply give up and stop reading daily.
25 25
26Thus, I found a way to deliver poetry to myself in plain-text format, on a daily 26Thus, I found a way to deliver poetry to myself in plain-text format, on a daily
27basis, and scheduled to deliver automatically. 27basis, and scheduled to deliver automatically.
@@ -31,8 +31,8 @@ basis, and scheduled to deliver automatically.
31This solution uses Python and email, so the following process requires the 31This solution uses Python and email, so the following process requires the
32following to be installed: 32following to be installed:
33 33
341. An SMTP server, which can be as easy as installing `mailutils` if you're on 341. An SMTP server, which can be as easy as installing `mailutils` if you're on a
35 a Debian-based distro. 35 Debian-based distro.
362. Python (& pip!) 362. Python (& pip!)
373. The following Python packages: `email`, `smtplib`, `json`, and `requests` 373. The following Python packages: `email`, `smtplib`, `json`, and `requests`
38 38
@@ -46,7 +46,7 @@ informational.
46This program starts with a simple import of the required packages, so I wanted 46This program starts with a simple import of the required packages, so I wanted
47to explain why each package is used: 47to explain why each package is used:
48 48
49``` python 49```python
50from email.mime.text import MIMEText # Required for translating MIMEText 50from email.mime.text import MIMEText # Required for translating MIMEText
51import smtplib # Required to process the SMTP mail delivery 51import smtplib # Required to process the SMTP mail delivery
52import json # Required to parse the poetry API results 52import json # Required to parse the poetry API results
@@ -55,41 +55,41 @@ import requests # Required to send out a request to the API
55 55
56## Sending the API Request 56## Sending the API Request
57 57
58Next, we need to actually send the API request. In my case, I'm calling a 58Next, we need to actually send the API request. In my case, I'm calling a random
59random poem from the entire API. If you want, you can call specific poems or 59poem from the entire API. If you want, you can call specific poems or authors
60authors from this API. 60from this API.
61 61
62``` python 62```python
63json_data = requests.get('https://poetrydb.org/random').json() 63json_data = requests.get('https://poetrydb.org/random').json()
64``` 64```
65 65
66This gives us the following result in JSON: 66This gives us the following result in JSON:
67 67
68``` json 68```json
69[ 69[
70 { 70 {
71 "title": "Sonnet XXII: With Fools and Children", 71 "title": "Sonnet XXII: With Fools and Children",
72 "author": "Michael Drayton", 72 "author": "Michael Drayton",
73 "lines": [ 73 "lines": [
74 "To Folly", 74 "To Folly",
75 "", 75 "",
76 "With fools and children, good discretion bears;", 76 "With fools and children, good discretion bears;",
77 "Then, honest people, bear with Love and me,", 77 "Then, honest people, bear with Love and me,",
78 "Nor older yet, nor wiser made by years,", 78 "Nor older yet, nor wiser made by years,",
79 "Amongst the rest of fools and children be;", 79 "Amongst the rest of fools and children be;",
80 "Love, still a baby, plays with gauds and toys,", 80 "Love, still a baby, plays with gauds and toys,",
81 "And, like a wanton, sports with every feather,", 81 "And, like a wanton, sports with every feather,",
82 "And idiots still are running after boys,", 82 "And idiots still are running after boys,",
83 "Then fools and children fitt'st to go together.", 83 "Then fools and children fitt'st to go together.",
84 "He still as young as when he first was born,", 84 "He still as young as when he first was born,",
85 "No wiser I than when as young as he;", 85 "No wiser I than when as young as he;",
86 "You that behold us, laugh us not to scorn;", 86 "You that behold us, laugh us not to scorn;",
87 "Give Nature thanks you are not such as we.", 87 "Give Nature thanks you are not such as we.",
88 "Yet fools and children sometimes tell in play", 88 "Yet fools and children sometimes tell in play",
89 "Some, wise in show, more fools indeed than they." 89 "Some, wise in show, more fools indeed than they."
90 ], 90 ],
91 "linecount": "15" 91 "linecount": "15"
92 } 92 }
93] 93]
94``` 94```
95 95
@@ -102,17 +102,17 @@ presented by the API.
102For the actual poem content, we need to loop over each line in the `lines` 102For the actual poem content, we need to loop over each line in the `lines`
103variable since each line is a separate string by default. 103variable since each line is a separate string by default.
104 104
105> You *could* also extract the title or author and make another call out to the 105> You _could_ also extract the title or author and make another call out to the
106> API to avoid having to build the plaintext poem with a loop, but it just 106> API to avoid having to build the plaintext poem with a loop, but it just
107> doesn't make sense to me to send multiple requests when we can create a 107> doesn't make sense to me to send multiple requests when we can create a simple
108> simple loop on our local machine to work with the data we already have. 108> loop on our local machine to work with the data we already have.
109> 109>
110> For 110> For
111> [example](https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text), 111> [example](https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text),
112> look at the raw data response of this link to see the poem's lines returned 112> look at the raw data response of this link to see the poem's lines returned in
113> in plaintext. 113> plaintext.
114 114
115``` python 115```python
116title = json_data[0]['title'] 116title = json_data[0]['title']
117author = json_data[0]['author'] 117author = json_data[0]['author']
118line_count = json_data[0]['linecount'] 118line_count = json_data[0]['linecount']
@@ -130,7 +130,7 @@ For my daily email, I want to see the title of the poem first, followed by the
130author, then a blank line, and finally the full poem. This code snippet combines 130author, then a blank line, and finally the full poem. This code snippet combines
131that data and packages it into a MIMEText container, ready to be emailed. 131that data and packages it into a MIMEText container, ready to be emailed.
132 132
133``` python 133```python
134msg_body = title + "\n" + author + "\n\n" + lines 134msg_body = title + "\n" + author + "\n\n" + lines
135msg = MIMEText(msg_body) 135msg = MIMEText(msg_body)
136``` 136```
@@ -138,7 +138,7 @@ msg = MIMEText(msg_body)
138Before we send the email, we need to prepare the metadata (subject, from, to, 138Before we send the email, we need to prepare the metadata (subject, from, to,
139etc.): 139etc.):
140 140
141``` python 141```python
142sender_email = 'example@server.local' 142sender_email = 'example@server.local'
143recipient_emails = ['user@example.com'] 143recipient_emails = ['user@example.com']
144msg['Subject'] = 'Your Daily Poem (' + line_count + ' lines)' 144msg['Subject'] = 'Your Daily Poem (' + line_count + ' lines)'
@@ -152,7 +152,7 @@ Now that I have everything ready to be emailed, the last step is to simply
152connect to an SMTP server and send the email out to the recipients. In my case, 152connect to an SMTP server and send the email out to the recipients. In my case,
153I installed `mailutils` on Ubuntu and let my SMTP server be `localhost`. 153I installed `mailutils` on Ubuntu and let my SMTP server be `localhost`.
154 154
155``` python 155```python
156smtp_server = 'localhost' 156smtp_server = 'localhost'
157s = smtplib.SMTP(smtp_server) 157s = smtplib.SMTP(smtp_server)
158s.sendmail(sender_email, recipient_emails, msg.as_string()) 158s.sendmail(sender_email, recipient_emails, msg.as_string())
@@ -164,7 +164,7 @@ s.quit()
164Instead of including a screenshot, I've copied the contents of the email that 164Instead of including a screenshot, I've copied the contents of the email that
165was delivered to my inbox below since I set this process up in plaintext format. 165was delivered to my inbox below since I set this process up in plaintext format.
166 166
167``` txt 167```txt
168Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC) 168Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
169From: REDACTED 169From: REDACTED
170To: REDACTED 170To: REDACTED
@@ -206,7 +206,7 @@ In the file, simply paste the following snippet at the bottom of the file and
206ensure that the file path is correctly pointing to wherever you saved your 206ensure that the file path is correctly pointing to wherever you saved your
207Python script: 207Python script:
208 208
209``` config 209```config
2100 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py 2100 8 ** ** ** python3 /home/<your_user>/dailypoem/main.py
211``` 211```
212 212
content/blog/2022-06-24-fedora-i3.md +71 −76
@@ -7,60 +7,56 @@ draft = false
7 7
8# Leaving macOS 8# Leaving macOS
9 9
10As I noted [in a recent post](../foss-macos-apps), I have been planning 10As I noted [in a recent post](../foss-macos-apps), I have been planning on
11on migrating from macOS back to a Linux-based OS. I am happy to say that 11migrating from macOS back to a Linux-based OS. I am happy to say that I have
12I have finally completed my migration and am now stuck in the wonderful 12finally completed my migration and am now stuck in the wonderful world of Linux
13world of Linux again. 13again.
14 14
15My decision to leave macOS really came down to just a few important 15My decision to leave macOS really came down to just a few important things:
16things: 16
17 17- Apple Security (Gatekeeper) restricting me from running any software I want.
18- Apple Security (Gatekeeper) restricting me from running any software I want. 18 Even if you disable Gatekeeper and allow software to bypass the rest of the
19 Even if you disable Gatekeeper and allow software to bypass the rest of the 19 device installation security, you still have to repeat that process every
20 device installation security, you still have to repeat that process every time 20 time the allowed software is updated.
21 the allowed software is updated. 21- macOS sends out nearly constant connections, pings, telemetry, etc. to a
22- macOS sends out nearly constant connections, pings, telemetry, etc. to a 22 myriad of mysterious Apple services. I'm not even going to dive into how
23 myriad of mysterious Apple services. I'm not even going to dive into how many 23 many macOS apps have constant telemetry on, as well.
24 macOS apps have constant telemetry on, as well. 24- Lastly, I just _really_ missed the customization and freedom that comes with
25- Lastly, I just *really* missed the customization and freedom that comes with 25 Linux. Being able to switch to entirely new kernel, OS, or desktop within
26 Linux. Being able to switch to entirely new kernel, OS, or desktop within 26 minutes is a freedom I took for granted when I switched to macOS.
27 minutes is a freedom I took for granted when I switched to macOS. 27
28 28Now that I've covered macOS, I'm going to move on to more exciting topics: my
29Now that I've covered macOS, I'm going to move on to more exciting 29personal choice of OS, DE, and various customizations I'm using.
30topics: my personal choice of OS, DE, and various customizations I'm
31using.
32 30
33# Fedora 31# Fedora
34 32
35After trying a ton of distros (I think I booted and tested around 20-25 33After trying a ton of distros (I think I booted and tested around 20-25
36distros), I finally landed on [Fedora Linux](https://getfedora.org/). I 34distros), I finally landed on [Fedora Linux](https://getfedora.org/). I have
37have quite a bit of experience with Fedora and enjoy the 35quite a bit of experience with Fedora and enjoy the `dnf` package manager.
38`dnf` package manager. Fedora allows me to keep up-to-date 36Fedora allows me to keep up-to-date with recent software (I'm looking at you,
39with recent software (I'm looking at you, Debian), but still provides a 37Debian), but still provides a level of stability you don't find in every distro.
40level of stability you don't find in every distro. 38
41 39In a very close second place was Arch Linux, as well as its spin-off: Garuda
42In a very close second place was Arch Linux, as well as its spin-off: 40Linux (Garuda w/ sway is _beautiful_). Arch is great for compatibility and the
43Garuda Linux (Garuda w/ sway is *beautiful*). Arch is great for 41massive community it has, but I have just never had the time to properly sit
44compatibility and the massive community it has, but I have just never 42down and learn the methodology behind their packaging systems.
45had the time to properly sit down and learn the methodology behind their 43
46packaging systems. 44Basically, everything else I tested was unacceptable in at least one way or
47 45another. Void (`glibc`) was great, but doesn't support all the software I need.
48Basically, everything else I tested was unacceptable in at least one way 46Slackware worked well as a tui, but I wasn't skilled enough to get a tiling
49or another. Void (`glibc`) was great, but doesn't support 47window manager (WM) working on it.
50all the software I need. Slackware worked well as a tui, but I wasn't
51skilled enough to get a tiling window manager (WM) working on it.
52 48
53## i3 49## i3
54 50
55One of the reasons I settled on Fedora is that it comes with an official 51One of the reasons I settled on Fedora is that it comes with an official i3
56i3 spin. Being able to use a tiling WM, such as i3 or sway, is one of 52spin. Being able to use a tiling WM, such as i3 or sway, is one of the biggest
57the biggest things I wanted to do as soon as I adopted Linux again. 53things I wanted to do as soon as I adopted Linux again.
58 54
59I will probably set up a dotfile repository soon, so that I don't lose 55I will probably set up a dotfile repository soon, so that I don't lose any of my
60any of my configurations, but nothing big has been configured thus far. 56configurations, but nothing big has been configured thus far.
61 57
62The two main things I have updated in i3wm are natural scrolling and 58The two main things I have updated in i3wm are natural scrolling and binding my
63binding my brightness keys to the `brightnessctl` program. 59brightness keys to the `brightnessctl` program.
64 60
651. Natural Scrolling 611. Natural Scrolling
66 62
@@ -70,12 +66,12 @@ binding my brightness keys to the `brightnessctl` program.
70 sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf 66 sudo nano /usr/share/X11/xorg.conf.d/40-libinput.conf
71 ``` 67 ```
72 68
73 Within the `40-libinput.conf` file, find the following 69 Within the `40-libinput.conf` file, find the following input sections and
74 input sections and enable the natural scrolling option. 70 enable the natural scrolling option.
75 71
76 This is the `pointer` section: 72 This is the `pointer` section:
77 73
78 ``` conf 74 ```conf
79 Section "InputClass" 75 Section "InputClass"
80 Identifier "libinput pointer catchall" 76 Identifier "libinput pointer catchall"
81 MatchIsPointer "on" 77 MatchIsPointer "on"
@@ -87,7 +83,7 @@ binding my brightness keys to the `brightnessctl` program.
87 83
88 This is the `touchpad` section: 84 This is the `touchpad` section:
89 85
90 ``` conf 86 ```conf
91 Section "InputClass" 87 Section "InputClass"
92 Identifier "libinput touchpad catchall" 88 Identifier "libinput touchpad catchall"
93 MatchIsTouchpad "on" 89 MatchIsTouchpad "on"
@@ -99,8 +95,8 @@ binding my brightness keys to the `brightnessctl` program.
99 95
1002. Enabling Brightness Keys 962. Enabling Brightness Keys
101 97
102 Likewise, enabling brightness key functionality is as simple as 98 Likewise, enabling brightness key functionality is as simple as binding the
103 binding the keys to the `brightnessctl` program. 99 keys to the `brightnessctl` program.
104 100
105 To do this, open up your i3 config file. Mine is located here: 101 To do this, open up your i3 config file. Mine is located here:
106 102
@@ -108,7 +104,7 @@ binding my brightness keys to the `brightnessctl` program.
108 nano /home/<my-user>/.config/i3/config 104 nano /home/<my-user>/.config/i3/config
109 ``` 105 ```
110 106
111 ``` conf 107 ```conf
112 # Use brightnessctl to adjust brightness. 108 # Use brightnessctl to adjust brightness.
113 bindsym XF86MonBrightnessDown exec --no-startup-id brightnessctl --min-val=2 -q set 3%- 109 bindsym XF86MonBrightnessDown exec --no-startup-id brightnessctl --min-val=2 -q set 3%-
114 bindsym XF86MonBrightnessUp exec --no-startup-id brightnessctl -q set 3%+ 110 bindsym XF86MonBrightnessUp exec --no-startup-id brightnessctl -q set 3%+
@@ -116,43 +112,42 @@ binding my brightness keys to the `brightnessctl` program.
116 112
1173. `polybar` 1133. `polybar`
118 114
119 Instead of using the default `i3status` bar, I have opted 115 Instead of using the default `i3status` bar, I have opted to use `polybar`
120 to use `polybar` instead (as you can also see in the 116 instead (as you can also see in the screenshot above).
121 screenshot above).
122 117
123 My config for this menu bar is basically just the default settings 118 My config for this menu bar is basically just the default settings with
124 with modified colors and an added battery block to quickly show me 119 modified colors and an added battery block to quickly show me the machine's
125 the machine's battery info. 120 battery info.
126 121
1274. `alacritty` 1224. `alacritty`
128 123
129 Not much to say on this part yet, as I haven't configured it much, 124 Not much to say on this part yet, as I haven't configured it much, but I
130 but I installed `alacritty` as my default terminal, and I 125 installed `alacritty` as my default terminal, and I am using `zsh` and the
131 am using `zsh` and the shell. 126 shell.
132 127
133# Software Choices 128# Software Choices
134 129
135Again, I'm not going to say much that I haven't said yet in other blog 130Again, I'm not going to say much that I haven't said yet in other blog posts, so
136posts, so I'll just do a quick rundown of the apps I installed 131I'll just do a quick rundown of the apps I installed immediately after I set up
137immediately after I set up the environment. 132the environment.
138 133
139Flatpak Apps: 134Flatpak Apps:
140 135
141- Cryptomator 136- Cryptomator
142- pCloud 137- pCloud
143- Signal 138- Signal
144 139
145Fedora Packages: 140Fedora Packages:
146 141
147- gomuks 142- gomuks
148- neomutt 143- neomutt
149- neofetch 144- neofetch
150- Firefox 145- Firefox
151 - uBlock Origin 146 - uBlock Origin
152 - Bitwarden 147 - Bitwarden
153 - Stylus 148 - Stylus
154 - Privacy Redirect 149 - Privacy Redirect
155 150
156Other: 151Other:
157 152
158- exiftool 153- exiftool
content/blog/2022-07-01-git-server.md +30 −30
@@ -17,22 +17,22 @@ anywhere.
17Before I dive into the details, I want to state a high-level summary of my 17Before I dive into the details, I want to state a high-level summary of my
18self-hosted Git approach: 18self-hosted Git approach:
19 19
20- This method uses the `ssh://` (read & write) and `git://` (read-only) 20- This method uses the `ssh://` (read & write) and `git://` (read-only)
21 protocols for push and pull access. 21 protocols for push and pull access.
22 - For the `git://` protocol, I create a `git-daemon-export-ok` file in any 22 - For the `git://` protocol, I create a `git-daemon-export-ok` file in any
23 repository that I want to be cloneable by anyone. 23 repository that I want to be cloneable by anyone.
24 - The web interface I am using (`cgit`) allows simple HTTP cloning by default. 24 - The web interface I am using (`cgit`) allows simple HTTP cloning by
25 I do not disable this setting as I want beginners to be able to clone one of 25 default. I do not disable this setting as I want beginners to be able to
26 my repositories even if they don't know the proper method. 26 clone one of my repositories even if they don't know the proper method.
27- I am not enabling Smart HTTPS for any repositories. Updates to repositories 27- I am not enabling Smart HTTPS for any repositories. Updates to repositories
28 must be pushed via SSH. 28 must be pushed via SSH.
29- Beyond the actual repository management, I am using `cgit` for the front-end 29- Beyond the actual repository management, I am using `cgit` for the front-end
30 web interface. 30 web interface.
31 - If you use the `scan-path=<path>` configuration in the `cgitrc` 31 - If you use the `scan-path=<path>` configuration in the `cgitrc`
32 configuration file to automatically find repositories, you can't exclude a 32 configuration file to automatically find repositories, you can't exclude
33 repository from `cgit` if it's stored within the path that `cgit` reads. To 33 a repository from `cgit` if it's stored within the path that `cgit`
34 host private repositories, you'd need to set up another directory that 34 reads. To host private repositories, you'd need to set up another
35 `cgit` can't read. 35 directory that `cgit` can't read.
36 36
37# Assumptions 37# Assumptions
38 38
@@ -106,7 +106,7 @@ sudo nano /etc/ssh/sshd_config
106Within this file, find the following settings and set them to the values I am 106Within this file, find the following settings and set them to the values I am
107showing below: 107showing below:
108 108
109``` conf 109```conf
110PermitRootLogin no 110PermitRootLogin no
111PasswordAuthentication no 111PasswordAuthentication no
112AuthenticationMethods publickey 112AuthenticationMethods publickey
@@ -177,8 +177,8 @@ other than the standard git commands.
177 177
178# Opening the Firewall 178# Opening the Firewall
179 179
180Don't forget to open up ports on the device firewall and network firewall if 180Don't forget to open up ports on the device firewall and network firewall if you
181you want to access these repositories publicly. If you're using default ports, 181want to access these repositories publicly. If you're using default ports,
182forward ports `22` (ssh) and `9418` (git) from your router to your server's IP 182forward ports `22` (ssh) and `9418` (git) from your router to your server's IP
183address. 183address.
184 184
@@ -203,7 +203,7 @@ your `~/.ssh/config` file:
203nano ~/.ssh/config 203nano ~/.ssh/config
204``` 204```
205 205
206``` conf 206```conf
207Host git.example.com 207Host git.example.com
208 # HostName can be a URL or an IP address 208 # HostName can be a URL or an IP address
209 HostName git.example.com 209 HostName git.example.com
@@ -215,8 +215,8 @@ Host git.example.com
215 215
216There are two main syntaxes you can use to manage git over SSH: 216There are two main syntaxes you can use to manage git over SSH:
217 217
218- `git clone [user@]server:project.git` 218- `git clone [user@]server:project.git`
219- `git clone ssh://[user@]server/project.git` 219- `git clone ssh://[user@]server/project.git`
220 220
221I prefer the first, which is an `scp`-like syntax. To test it, try to clone the 221I prefer the first, which is an `scp`-like syntax. To test it, try to clone the
222test repository you set up on the server: 222test repository you set up on the server:
@@ -238,7 +238,7 @@ sudo nano /etc/systemd/system/git-daemon.service
238 238
239Inside the `git-daemon.service` file, paste the following: 239Inside the `git-daemon.service` file, paste the following:
240 240
241``` conf 241```conf
242[Unit] 242[Unit]
243Description=Start Git Daemon 243Description=Start Git Daemon
244 244
@@ -322,7 +322,7 @@ mkdir ~/cgit && cd ~/cgit
322nano docker-compose.yml 322nano docker-compose.yml
323``` 323```
324 324
325``` conf 325```conf
326# docker-compose.yml 326# docker-compose.yml
327version: '3' 327version: '3'
328 328
@@ -361,7 +361,7 @@ configuration file:
361sudo nano /etc/nginx/sites-available/git.example.com 361sudo nano /etc/nginx/sites-available/git.example.com
362``` 362```
363 363
364``` conf 364```conf
365server { 365server {
366 listen 80; 366 listen 80;
367 server_name git.example.com; 367 server_name git.example.com;
@@ -430,7 +430,7 @@ cd /git/example.git
430nano config 430nano config
431``` 431```
432 432
433``` conf 433```conf
434[gitweb] 434[gitweb]
435 owner = "YourName" 435 owner = "YourName"
436``` 436```
@@ -451,7 +451,7 @@ Below is an example configuration for `cgitrc`. You can find all the
451configuration options within the [configuration manual] 451configuration options within the [configuration manual]
452(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>). 452(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>).
453 453
454``` conf 454```conf
455css=/cgit.css 455css=/cgit.css
456logo=/logo.png 456logo=/logo.png
457favicon=/favicon.png 457favicon=/favicon.png
@@ -569,8 +569,8 @@ files](https://git.zx2c4.com/cgit/tree/filters), repeat the `curl` and `chmod`
569process above for whichever files you need. 569process above for whichever files you need.
570 570
571However, formatting will not work quite yet since the Docker cgit container 571However, formatting will not work quite yet since the Docker cgit container
572we're using doesn't have the formatting package installed. You can install 572we're using doesn't have the formatting package installed. You can install this
573this easily by install Python 3+ and the `pygments` package: 573easily by install Python 3+ and the `pygments` package:
574 574
575```sh 575```sh
576# Enter the container's command line 576# Enter the container's command line
@@ -592,7 +592,7 @@ commands every time you kill and restart the container!**
592If not done already, we need to add the following variables to our `cgitrc` file 592If not done already, we need to add the following variables to our `cgitrc` file
593in order for `cgit` to know where our filtering files are: 593in order for `cgit` to know where our filtering files are:
594 594
595``` conf 595```conf
596# Highlight source code with python pygments-based highlighter 596# Highlight source code with python pygments-based highlighter
597source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py 597source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
598 598
content/blog/2022-07-14-gnupg.md +40 −40
@@ -47,45 +47,45 @@ I am not doing an in-depth explanation here in order to keep the focus on GPG
47and not encryption algorithms. If you want a deep dive into cryptography or 47and not encryption algorithms. If you want a deep dive into cryptography or
48encryption algorithms, please read my other posts: 48encryption algorithms, please read my other posts:
49 49
50- [AES Encryption](../aes-encryption/) (2018) 50- [AES Encryption](../aes-encryption/) (2018)
51- [Cryptography Basics](../cryptography-basics/) (2020) 51- [Cryptography Basics](../cryptography-basics/) (2020)
52 52
53## Vulnerabilities 53## Vulnerabilities
54 54
55As of 2022-07-14, there are a few different vulnerabilities associated with GPG 55As of 2022-07-14, there are a few different vulnerabilities associated with GPG
56or the libraries it uses: 56or the libraries it uses:
57 57
58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one 58- GPG versions 1.0.2--1.2.3 contains a bug where "as soon as one
59 (GPG-generated) ElGamal signature of an arbitrary message is released, one can 59 (GPG-generated) ElGamal signature of an arbitrary message is released, one
60 recover the signer's private key in less than a second on a PC." 60 can recover the signer's private key in less than a second on a PC."
61 ([Source](https://www.di.ens.fr/~pnguyen/pub_Ng04.htm)) 61 ([Source](https://www.di.ens.fr/~pnguyen/pub_Ng04.htm))
62- GPG versions prior to 1.4.2.1 contain a false positive signature verification 62- GPG versions prior to 1.4.2.1 contain a false positive signature
63 bug. 63 verification bug.
64 ([Source](https://lists.gnupg.%20org/pipermail/gnupg-announce/2006q1/000211.html)) 64 ([Source](https://lists.gnupg.%20org/pipermail/gnupg-announce/2006q1/000211.html))
65- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned data. ( 65- GPG versions prior to 1.4.2.2 cannot detect injection of unsigned data. (
66 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html)) 66 [Source](https://lists.gnupg.org/pipermail/gnupg-announce/2006q1/000218.html))
67- Libgcrypt, a library used by GPG, contained a bug which enabled full key 67- Libgcrypt, a library used by GPG, contained a bug which enabled full key
68 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG 68 recovery for RSA-1024 and some RSA-2048 keys. This was resolved in a GPG
69 update in 2017. ([Source](https://lwn.net/Articles/727179/)) 69 update in 2017. ([Source](https://lwn.net/Articles/727179/))
70- The [ROCA Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability) 70- The [ROCA Vulnerability](https://en.wikipedia.org/wiki/ROCA_vulnerability)
71 affects RSA keys generated by YubiKey 4 tokens. 71 affects RSA keys generated by YubiKey 4 tokens.
72 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf)) 72 ([Source](https://crocs.fi.%20muni.cz/_media/public/papers/nemec_roca_ccs17_preprint.pdf))
73- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows an 73- The [SigSpoof Attack](https://en.wikipedia.org/wiki/SigSpoof) allows an
74 attacker to spoof digital signatures. 74 attacker to spoof digital signatures.
75 ([Source](https://arstechnica.%20com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/)) 75 ([Source](https://arstechnica.%20com/information-technology/2018/06/decades-old-pgp-bug-allowed-hackers-to-spoof-just-about-anyones-signature/))
76- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow, 76- Libgcrypt 1.9.0 contains a severe flaw related to a heap buffer overflow,
77 fixed in Libgcrypt 1.9.1 77 fixed in Libgcrypt 1.9.1
78 ([Source](https://web.archive.%20org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/)) 78 ([Source](https://web.archive.%20org/web/20210221012505/https://www.theregister.com/2021/01/29/severe_libgcrypt_bug/))
79 79
80### Platforms 80### Platforms
81 81
82Originally developed as a command-line program for *nix systems, GPG now has a 82Originally developed as a command-line program for \*nix systems, GPG now has a
83wealth of front-end applications and libraries available for end-users. However, 83wealth of front-end applications and libraries available for end-users. However,
84the most recommended programs remain the same: 84the most recommended programs remain the same:
85 85
86- [GnuPG](https://gnupg.org) for Linux (depending on distro) 86- [GnuPG](https://gnupg.org) for Linux (depending on distro)
87- [Gpg4win](https://gpg4win.org) for Windows 87- [Gpg4win](https://gpg4win.org) for Windows
88- [GPGTools](https://gpgtools.org) for macOS 88- [GPGTools](https://gpgtools.org) for macOS
89 89
90# Creating a Key Pair 90# Creating a Key Pair
91 91
@@ -170,11 +170,11 @@ interface.
170 170
171As noted in RFC 4880, the general functions of OpenPGP are as follows: 171As noted in RFC 4880, the general functions of OpenPGP are as follows:
172 172
173- digital signatures 173- digital signatures
174- encryption 174- encryption
175- compression 175- compression
176- Radix-64 conversion 176- Radix-64 conversion
177- key management and certificate services 177- key management and certificate services
178 178
179From this, you can probably gather that the main use of GPG is for encrypting 179From this, you can probably gather that the main use of GPG is for encrypting
180data and/or signing the data with a key. The purpose of encrypting data with GPG 180data and/or signing the data with a key. The purpose of encrypting data with GPG
@@ -195,10 +195,10 @@ public key, the recipient(s) of the message can verify that the message was
195signed with my personal key. 195signed with my personal key.
196 196
197The second process, regarding the actual encryption of the message and its 197The second process, regarding the actual encryption of the message and its
198contents, works by using a combination of the sender's keys and the 198contents, works by using a combination of the sender's keys and the recipient's
199recipient's keys. This process may vary slightly by implementation, but it most 199keys. This process may vary slightly by implementation, but it most commonly
200commonly uses asymmetric cryptography, also known as public-key cryptography. In 200uses asymmetric cryptography, also known as public-key cryptography. In this
201this version of encryption, the sender's private key to sign the message and a 201version of encryption, the sender's private key to sign the message and a
202combination of the sender's keys and the recipient's public key to encrypt the 202combination of the sender's keys and the recipient's public key to encrypt the
203message. 203message.
204 204
@@ -275,8 +275,8 @@ In order to verify signed data, a user needs to have:
2752. A signature file 2752. A signature file
2763. The public GPG key of the signer 2763. The public GPG key of the signer
277 277
278Once the signer's public key is imported on the user's system, and they have 278Once the signer's public key is imported on the user's system, and they have the
279the data and signature, they can verify the data with the following commands: 279data and signature, they can verify the data with the following commands:
280 280
281```sh 281```sh
282# If the signature is attached to the data 282# If the signature is attached to the data
@@ -296,5 +296,5 @@ them.
296 296
297Otherwise, the best option is to use a keyserver, such as: 297Otherwise, the best option is to use a keyserver, such as:
298 298
299- [pgp.mit.edu](https://pgp.mit.edu) 299- [pgp.mit.edu](https://pgp.mit.edu)
300- [keys.openpgp.org](https://keys.openpgp.org) 300- [keys.openpgp.org](https://keys.openpgp.org)
content/blog/2022-07-25-curseradio.md +3 −4
@@ -12,9 +12,8 @@ While exploring some interesting Linux applications, I stumbled across
12player based on Python. 12player based on Python.
13 13
14This application is fantastic and incredibly easy to install, so I wanted to 14This application is fantastic and incredibly easy to install, so I wanted to
15dedicate a post today to this app. Let's look at the features within the app 15dedicate a post today to this app. Let's look at the features within the app and
16and then walk through the installation process I took to get `curseradio` 16then walk through the installation process I took to get `curseradio` working.
17working.
18 17
19# Features 18# Features
20 19
@@ -35,7 +34,7 @@ radio player in the `Favourites` category.
35## Commands/Shortcuts 34## Commands/Shortcuts
36 35
37| Key(s) | Command | 36| Key(s) | Command |
38|------------|---------------------------------| 37| ---------- | ------------------------------- |
39| ↑, ↓ | navigate | 38| ↑, ↓ | navigate |
40| PgUp, PgDn | navigate quickly | 39| PgUp, PgDn | navigate quickly |
41| Home, End | to top/bottom | 40| Home, End | to top/bottom |
content/blog/2022-07-30-flac-to-opus.md +13 −13
@@ -16,7 +16,7 @@ of the files, especially if you're using a weak connection.
16 16
17So, in order to archive the music in a lossless format and still be able to 17So, in order to archive the music in a lossless format and still be able to
18stream it easily, I opted to create a copy of my FLAC files in the [Opus audio 18stream it easily, I opted to create a copy of my FLAC files in the [Opus audio
19codec](https://en.wikipedia.org/wiki/Opus_(audio_format)). This allows me to 19codec](<https://en.wikipedia.org/wiki/Opus_(audio_format)>). This allows me to
20archive a quality, lossless version of the music and then point my streaming 20archive a quality, lossless version of the music and then point my streaming
21service to the smaller, stream-ready version. 21service to the smaller, stream-ready version.
22 22
@@ -47,20 +47,20 @@ following logic into the script.
47 47
48You **MUST** edit the following variables in order for it to work: 48You **MUST** edit the following variables in order for it to work:
49 49
50- `source`: The source directory where your FLAC files are stored. 50- `source`: The source directory where your FLAC files are stored.
51- `dest`: The destination directory where you want the resulting Opus files to 51- `dest`: The destination directory where you want the resulting Opus files to
52 be stored. 52 be stored.
53 53
54You **MAY** want to edit the following variables to suit your needs: 54You **MAY** want to edit the following variables to suit your needs:
55 55
56- `filename`: If you are converting to a file format other than Opus, you'll 56- `filename`: If you are converting to a file format other than Opus, you'll
57 need to edit this so that your resulting files have the correct filename 57 need to edit this so that your resulting files have the correct filename
58 extension. 58 extension.
59- `reldir`: This variable can be edited to strip out more leading directories in 59- `reldir`: This variable can be edited to strip out more leading directories
60 the file path. As you'll see later, I ignore this for now and simply clean it 60 in the file path. As you'll see later, I ignore this for now and simply
61 up afterward. 61 clean it up afterward.
62- `opusenc`: This is the actual conversion process. You may want to edit the 62- `opusenc`: This is the actual conversion process. You may want to edit the
63 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher. 63 bitrate to suit your needs. I set mine at 128 but some prefer 160 or higher.
64 64
65```sh 65```sh
66#!/bin/bash 66#!/bin/bash
@@ -168,7 +168,7 @@ du -h --max-depth=1 .
168 168
169In my case, my small library went from 78GB to 6.3GB! 169In my case, my small library went from 78GB to 6.3GB!
170 170
171``` txt 171```txt
17278G ./archives 17278G ./archives
1736.3G ./library 1736.3G ./library
174``` 174```
content/blog/2022-07-31-bash-it.md +9 −9
@@ -8,19 +8,19 @@ draft = false
8# Bash 8# Bash
9 9
10For those who are not familiar, 10For those who are not familiar,
11[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is a Unix shell that is 11[Bash](<https://en.wikipedia.org/wiki/Bash_(Unix_shell)>) is a Unix shell that
12used as the default login shell for most Linux distributions. This shell and 12is used as the default login shell for most Linux distributions. This shell and
13command processor should be familiar if you've used Linux (or older version of 13command processor should be familiar if you've used Linux (or older version of
14macOS) before. 14macOS) before.
15 15
16However, bash is not the only option. There are numerous other shells that 16However, bash is not the only option. There are numerous other shells that
17exist. Here are some popular examples: 17exist. Here are some popular examples:
18 18
19- [zsh](https://en.wikipedia.org/wiki/Z_shell) 19- [zsh](https://en.wikipedia.org/wiki/Z_shell)
20- [fish](https://en.wikipedia.org/wiki/Fish_(Unix_shell)) 20- [fish](<https://en.wikipedia.org/wiki/Fish_(Unix_shell)>)
21- [oksh](https://github.com/ibara/oksh) 21- [oksh](https://github.com/ibara/oksh)
22- [mksh](https://wiki.gentoo.org/wiki/Mksh) 22- [mksh](https://wiki.gentoo.org/wiki/Mksh)
23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell) 23- [dash](https://en.wikipedia.org/wiki/Debian_Almquist_shell)
24 24
25While each shell has its differences, bash is POSIX compliant and the default 25While each shell has its differences, bash is POSIX compliant and the default
26for many Linux users. Because of this, I am going to explore a program called 26for many Linux users. Because of this, I am going to explore a program called
@@ -110,7 +110,7 @@ This will provide you a list that looks like the following text block. Within
110this screen, you will be able to see all available options and which ones are 110this screen, you will be able to see all available options and which ones are
111currently enabled. 111currently enabled.
112 112
113``` txt 113```txt
114Alias Enabled? Description 114Alias Enabled? Description
115ag [ ] the silver searcher (ag) aliases 115ag [ ] the silver searcher (ag) aliases
116ansible [ ] ansible abbreviations 116ansible [ ] ansible abbreviations
@@ -148,7 +148,7 @@ bash-it show plugins
148 148
149You will see the following output showing enabled and disabled plugins: 149You will see the following output showing enabled and disabled plugins:
150 150
151``` txt 151```txt
152Plugin Enabled? Description 152Plugin Enabled? Description
153alias-completion [ ] 153alias-completion [ ]
154autojump [ ] Autojump configuration, see https://github.com/wting/autojump for more details 154autojump [ ] Autojump configuration, see https://github.com/wting/autojump for more details
content/blog/2022-08-31-privacy-com-changes.md +8 −8
@@ -14,9 +14,9 @@ order to continue using their accounts.
14[You can view the new cardholder agreement 14[You can view the new cardholder agreement
15here](https://privacy.com/commercial-cardholder-agreement). 15here](https://privacy.com/commercial-cardholder-agreement).
16 16
17When you log in, you'll be greeted with a pop-up window asking you to review 17When you log in, you'll be greeted with a pop-up window asking you to review and
18and agree to the new terms of use. You will also not be able to open any new 18agree to the new terms of use. You will also not be able to open any new cards
19cards until the terms are agreed to. 19until the terms are agreed to.
20 20
21## Changing from a "Prepaid Debit" Model to a "Charge Card" Model 21## Changing from a "Prepaid Debit" Model to a "Charge Card" Model
22 22
@@ -36,9 +36,9 @@ Privacy.com and set the merchant as one of their pre-set options, such as
36"Smiley's Corner Store" or "NSA Gift Shop." 36"Smiley's Corner Store" or "NSA Gift Shop."
37 37
38The new model still works with a bank account as a funding source, but the model 38The new model still works with a bank account as a funding source, but the model
39is changed so that you get a "line of credit" set according to a 14-day 39is changed so that you get a "line of credit" set according to a 14-day billing
40billing cycle. It seems that Privacy.com will now allow charges to be incurred 40cycle. It seems that Privacy.com will now allow charges to be incurred without
41without being immediately paid. 41being immediately paid.
42 42
43## Daily Payments and Available Credit 43## Daily Payments and Available Credit
44 44
@@ -83,8 +83,8 @@ off my prepaid debit payments, I have no interest in incurring charges that will
83need to be paid back at a later date. I also have no interest in submitting 83need to be paid back at a later date. I also have no interest in submitting
84personal information to Privacy.com. 84personal information to Privacy.com.
85 85
86This type of change toward a "buy it now, pay us later" model is concerning, 86This type of change toward a "buy it now, pay us later" model is concerning, and
87and I will be watching Privacy.com to see if they further their interests in the 87I will be watching Privacy.com to see if they further their interests in the
88credit model as time goes on. 88credit model as time goes on.
89 89
90Could we see them start charging interest, fees, etc.? I'm not sure, but this 90Could we see them start charging interest, fees, etc.? I'm not sure, but this
content/blog/2022-09-17-serenity-os.md +1 −1
@@ -24,7 +24,7 @@ Per their website:
24> other systems. 24> other systems.
25> 25>
26> Roughly speaking, the goal is a marriage between the aesthetic of late-1990s 26> Roughly speaking, the goal is a marriage between the aesthetic of late-1990s
27> productivity software and the power-user accessibility of late-2000s *nix. 27> productivity software and the power-user accessibility of late-2000s \*nix.
28> 28>
29> This is a system by us, for us, based on the things we like. 29> This is a system by us, for us, based on the things we like.
30 30
content/blog/2022-09-21-graphene-os.md +5 −5
@@ -92,9 +92,9 @@ To start, enable developer mode by going to `Settings` > `About` and tapping
92`Build Number` seven (7) times. You may need to enter your PIN to enable this 92`Build Number` seven (7) times. You may need to enter your PIN to enable this
93mode. 93mode.
94 94
95Once developer mode is enabled, go to `Settings` > `System` > `Devloper 95Once developer mode is enabled, go to `Settings` > `System` > `Devloper Options`
96Options` and enable OEM Unlocking, as well as USB or Wireless Debugging. In my 96and enable OEM Unlocking, as well as USB or Wireless Debugging. In my case, I
97case, I chose USB Debugging and performed all actions via USB cable. 97chose USB Debugging and performed all actions via USB cable.
98 98
99Once these options are enabled, plug the phone into the computer and execute the 99Once these options are enabled, plug the phone into the computer and execute the
100following command: 100following command:
@@ -104,8 +104,8 @@ adb devices
104``` 104```
105 105
106If an unauthorized error occurs, make sure the USB mode on the phone is changed 106If an unauthorized error occurs, make sure the USB mode on the phone is changed
107from charging to something like "File Transfer" or "PTP." You can find the 107from charging to something like "File Transfer" or "PTP." You can find the USB
108USB mode in the notification tray. 108mode in the notification tray.
109 109
110## Reboot Device 110## Reboot Device
111 111
content/blog/2022-10-04-mtp-linux.md +2 −2
@@ -20,8 +20,8 @@ confirm that switching to a USB 3.0 port seemed to cut out most of my issues.
20 20
21# Switch USB Preferences to MTP 21# Switch USB Preferences to MTP
22 22
23Secondly, you need to ensure that the phone's USB preferences/mode is changed 23Secondly, you need to ensure that the phone's USB preferences/mode is changed to
24to MTP or File Transfer once the phone is plugged in. Other modes will not allow 24MTP or File Transfer once the phone is plugged in. Other modes will not allow
25you to access the phone's file system. 25you to access the phone's file system.
26 26
27# Install `jmtpfs` 27# Install `jmtpfs`
content/blog/2022-10-04-syncthing.md +21 −21
@@ -11,8 +11,8 @@ If you've been looking around the self-hosted cloud storage space for a while,
11you've undoubtedly run into someone suggesting 11you've undoubtedly run into someone suggesting
12[Syncthing](https://syncthing.net) as an option. However, it is an unusual 12[Syncthing](https://syncthing.net) as an option. However, it is an unusual
13alternative for those users out there who are used to having a centralized cloud 13alternative for those users out there who are used to having a centralized cloud
14server that serves as the "controller" of the data and interacts with clients 14server that serves as the "controller" of the data and interacts with clients on
15on devices to fetch files. 15devices to fetch files.
16 16
17This post is a walkthrough of the Syncthing software, how I set up my personal 17This post is a walkthrough of the Syncthing software, how I set up my personal
18storage, and some pros and cons of using the software. 18storage, and some pros and cons of using the software.
@@ -114,10 +114,10 @@ per device.
114# My Personal Cloud Storage Set-up 114# My Personal Cloud Storage Set-up
115 115
116Personally, I use a model similar to a traditional cloud storage service. I have 116Personally, I use a model similar to a traditional cloud storage service. I have
117a "centralized" server running 24/7 that acts as an Introducer for my 117a "centralized" server running 24/7 that acts as an Introducer for my Syncthing
118Syncthing network. I think of this as my main storage and all other devices as 118network. I think of this as my main storage and all other devices as tertiary
119tertiary client devices. I will likely add additional servers as backups as time 119client devices. I will likely add additional servers as backups as time goes on
120goes on so that I don't have to rely on my laptop or phone as the only backups. 120so that I don't have to rely on my laptop or phone as the only backups.
121 121
122Currently, I have one desktop and one mobile device connected to the network, 122Currently, I have one desktop and one mobile device connected to the network,
123both running intermittently as they are not powered-on 24/7. 123both running intermittently as they are not powered-on 24/7.
@@ -139,24 +139,24 @@ iCloud, etc.), and privacy-focused cloud solutions (pCloud, Tresorit, etc.).
139 139
140**Pros:** 140**Pros:**
141 141
142- I've faced no data loss at all through my two-month trial run. 142- I've faced no data loss at all through my two-month trial run.
143- No third-parties store your data on their servers. 143- No third-parties store your data on their servers.
144- You have full control over your data and can take your data and leave at any 144- You have full control over your data and can take your data and leave at any
145 time. 145 time.
146- It's possible to encrypt client-side easily with software like Cryptomator. 146- It's possible to encrypt client-side easily with software like Cryptomator.
147- No proprietary clients or mounted volumes, just plain files and folders. 147- No proprietary clients or mounted volumes, just plain files and folders.
148 148
149**Cons:** 149**Cons:**
150 150
151- The learning curve is steeper than traditional cloud services and is focused 151- The learning curve is steeper than traditional cloud services and is focused
152 on a technical audience. 152 on a technical audience.
153- If a device needs to modify files in a Folder, the devices will need to sync 153- If a device needs to modify files in a Folder, the devices will need to sync
154 ALL files from the folder, which may be large. To avoid size restraints, split 154 ALL files from the folder, which may be large. To avoid size restraints,
155 large folders into smaller folders for syncing. 155 split large folders into smaller folders for syncing.
156- Syncing can be slow due to the clients/servers initially connecting or 156- Syncing can be slow due to the clients/servers initially connecting or
157 re-connecting after sleeping. 157 re-connecting after sleeping.
158- Multiple personal devices are required and require the user to own or rent 158- Multiple personal devices are required and require the user to own or rent
159 them as no third-party servers are involved in the storage of data. 159 them as no third-party servers are involved in the storage of data.
160 160
161Overall, I've had a great experience with Syncthing so far. I've had no data 161Overall, I've had a great experience with Syncthing so far. I've had no data
162loss, syncing has been quick and easy when changes are made to files, device 162loss, syncing has been quick and easy when changes are made to files, device
content/blog/2022-10-22-alpine-linux.md +28 −29
@@ -14,8 +14,8 @@ and apk as the package manager. According to their website, an Alpine container
14130 MB of storage." An actual bare metal machine is recommended to have 100 MB 14130 MB of storage." An actual bare metal machine is recommended to have 100 MB
15of RAM and 0-700 MB of storage space. 15of RAM and 0-700 MB of storage space.
16 16
17Historically, I've used Ubuntu's minimal installation image as my server OS 17Historically, I've used Ubuntu's minimal installation image as my server OS for
18for the last five years. Ubuntu worked well and helped as my original server 18the last five years. Ubuntu worked well and helped as my original server
19contained an nVidia GPU and no onboard graphics, so quite a few distros won't 19contained an nVidia GPU and no onboard graphics, so quite a few distros won't
20boot or install without a lot of tinkering. 20boot or install without a lot of tinkering.
21 21
@@ -53,24 +53,24 @@ setup-alpine
53The setup script will ask a series of questions to configure the system. Be sure 53The setup script will ask a series of questions to configure the system. Be sure
54to answer carefully or else you may have to re-configure the system after boot. 54to answer carefully or else you may have to re-configure the system after boot.
55 55
56- Keyboard Layout (Local keyboard language and usage mode, e.g., us and variant 56- Keyboard Layout (Local keyboard language and usage mode, e.g., us and
57 of us-nodeadkeys.) 57 variant of us-nodeadkeys.)
58- Hostname (The name for the computer.) 58- Hostname (The name for the computer.)
59- Network (For example, automatic IP address discovery with the "DHCP" 59- Network (For example, automatic IP address discovery with the "DHCP"
60 protocol.) 60 protocol.)
61- DNS Servers (Domain Name Servers to query. For privacy reasons, it is NOT 61- DNS Servers (Domain Name Servers to query. For privacy reasons, it is NOT
62 recommended to route every local request to servers like Google's 8.8.8.8.) 62 recommended to route every local request to servers like Google's 8.8.8.8.)
63- Timezone 63- Timezone
64- Proxy (Proxy server to use for accessing the web. Use "none" for direct 64- Proxy (Proxy server to use for accessing the web. Use "none" for direct
65 connections to the internet.) 65 connections to the internet.)
66- Mirror (From where to download packages. Choose the organization you trust 66- Mirror (From where to download packages. Choose the organization you trust
67 giving your usage patterns to.) 67 giving your usage patterns to.)
68- SSH (Secure SHell remote access server. "Openssh" is part of the default 68- SSH (Secure SHell remote access server. "Openssh" is part of the default
69 install image. Use "none" to disable remote login, e.g. on laptops.) 69 install image. Use "none" to disable remote login, e.g. on laptops.)
70- NTP (Network Time Protocol client used for keeping the system clock in sync 70- NTP (Network Time Protocol client used for keeping the system clock in sync
71 with a time-server. Package "chrony" is part of the default install image.) 71 with a time-server. Package "chrony" is part of the default install image.)
72- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as 72- Disk Mode (Select between diskless (disk="none"), "data" or "sys", as
73 described above.) 73 described above.)
74 74
75Once the setup script is finished, be sure to reboot the machine and remove the 75Once the setup script is finished, be sure to reboot the machine and remove the
76USB device. 76USB device.
@@ -82,8 +82,8 @@ reboot
82## Post-Installation 82## Post-Installation
83 83
84There are many things you can do once your Alpine Linux system is up and 84There are many things you can do once your Alpine Linux system is up and
85running, and it largely depends on what you'll use the machine for. I'm going 85running, and it largely depends on what you'll use the machine for. I'm going to
86to walk through my personal post-installation setup for my web server. 86walk through my personal post-installation setup for my web server.
87 87
881. Upgrade the System 881. Upgrade the System
89 89
@@ -96,8 +96,8 @@ to walk through my personal post-installation setup for my web server.
962. Adding a User 962. Adding a User
97 97
98 I needed to add a user so that I don't need to log in as root. Note that if 98 I needed to add a user so that I don't need to log in as root. Note that if
99 you're used to using the `sudo` command, you will now need to use the 99 you're used to using the `sudo` command, you will now need to use the `doas`
100 `doas` command on Alpine Linux. 100 command on Alpine Linux.
101 101
102 ```sh 102 ```sh
103 apk add doas 103 apk add doas
@@ -120,8 +120,7 @@ to walk through my personal post-installation setup for my web server.
120 doas nano /etc/apk/repositories 120 doas nano /etc/apk/repositories
121 ``` 121 ```
122 122
123 Uncomment the community line for whichever version of Alpine you're 123 Uncomment the community line for whichever version of Alpine you're running:
124 running:
125 124
126 ```sh 125 ```sh
127 /media/usb/apks 126 /media/usb/apks
@@ -258,9 +257,9 @@ doas lchsh git
258# Thoughts on Alpine 257# Thoughts on Alpine
259 258
260So far, I love Alpine Linux. I have no complaints about anything at this point, 259So far, I love Alpine Linux. I have no complaints about anything at this point,
261but I'm not completely finished with the migration yet. Once I'm able to 260but I'm not completely finished with the migration yet. Once I'm able to upgrade
262upgrade my hardware to a rack-mounted server, I will migrate Plex and Syncthing 261my hardware to a rack-mounted server, I will migrate Plex and Syncthing over to
263over to Alpine as well - possibly putting Plex into a container or VM. 262Alpine as well - possibly putting Plex into a container or VM.
264 263
265The performance is stellar, the `apk` package manager is seamless, and system 264The performance is stellar, the `apk` package manager is seamless, and system
266administration tasks are effortless. My only regret is that I didn't install 265administration tasks are effortless. My only regret is that I didn't install
content/blog/2022-11-07-self-hosting-matrix.md +8 −8
@@ -5,7 +5,7 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# Synpase 8# Synapse
9 9
10If you're reading this, you likely know that 10If you're reading this, you likely know that
11[Synapse](https://github.com/matrix-org/synapse/) is a popular 11[Synapse](https://github.com/matrix-org/synapse/) is a popular
@@ -72,7 +72,7 @@ are a lot of other configuration options found in the [Configuring
72Synapse](https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html) 72Synapse](https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html)
73documentation that can be enabled/disabled at any point. 73documentation that can be enabled/disabled at any point.
74 74
75``` yaml 75```yaml
76server_name: "example.com" 76server_name: "example.com"
77``` 77```
78 78
@@ -97,7 +97,7 @@ doas nano /etc/nginx/http.d/example.com.conf
97If you already have TLS certificates for this domain (`example.com`), you can 97If you already have TLS certificates for this domain (`example.com`), you can
98simply use the SSL configuration and point toward your TLS certificates. 98simply use the SSL configuration and point toward your TLS certificates.
99 99
100``` conf 100```conf
101server { 101server {
102 listen 443 ssl http2; 102 listen 443 ssl http2;
103 listen [::]:443 ssl http2; 103 listen [::]:443 ssl http2;
@@ -139,11 +139,11 @@ server {
139``` 139```
140 140
141If you need to generate TLS certificates (I recommend 141If you need to generate TLS certificates (I recommend
142[Certbot](https://certbot.eff.org/)), you'll need a more minimal Nginx conf 142[Certbot](https://certbot.eff.org/)), you'll need a more minimal Nginx conf file
143file before you can use the TLS-enabled example above. Instead, use this 143before you can use the TLS-enabled example above. Instead, use this
144configuration file during the Certbot certificate generation process: 144configuration file during the Certbot certificate generation process:
145 145
146``` conf 146```conf
147server { 147server {
148 server_name example.com; 148 server_name example.com;
149 location / { 149 location / {
@@ -196,8 +196,8 @@ Router from the internet to your server's IP address.
196 196
197## Adding Matrix Users 197## Adding Matrix Users
198 198
199Finally, if you didn't enable public registration in the `homeserver.yaml` 199Finally, if you didn't enable public registration in the `homeserver.yaml` file,
200file, you can manually create users via the command-line: 200you can manually create users via the command-line:
201 201
202```sh 202```sh
203cd ~/synapse 203cd ~/synapse
content/blog/2022-11-11-nginx-tmp-errors.md +5 −5
@@ -5,8 +5,8 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8*This is a brief post so that I personally remember the solution as it has 8_This is a brief post so that I personally remember the solution as it has
9occurred multiple times for me.* 9occurred multiple times for me._
10 10
11# The Problem 11# The Problem
12 12
@@ -45,7 +45,7 @@ doas chown -R nginx:nginx /var/lib/nginx
45sudo chown -R nginx:nginx /var/lib/nginx 45sudo chown -R nginx:nginx /var/lib/nginx
46``` 46```
47 47
48You *may* also be able to change the `proxy_temp_path` in your Nginx config, but 48You _may_ also be able to change the `proxy_temp_path` in your Nginx config, but
49I did not try this. Here's a suggestion I found online that may work if the 49I did not try this. Here's a suggestion I found online that may work if the
50above solution does not: 50above solution does not:
51 51
@@ -53,11 +53,11 @@ above solution does not:
53nano /etc/nginx/http.d/example.com.conf 53nano /etc/nginx/http.d/example.com.conf
54``` 54```
55 55
56``` conf 56```conf
57server { 57server {
58 ... 58 ...
59 59
60 # Set the proxy_temp_path to your preference, make sure it's owned by the 60 # Set the proxy_temp_path to your preference, make sure it's owned by the
61 # `nginx` user 61 # `nginx` user
62 proxy_temp_path /tmp; 62 proxy_temp_path /tmp;
63 63
content/blog/2022-11-27-server-build.md +19 −19
@@ -26,25 +26,25 @@ results of my server.
26 26
27I'll start by listing all the components I used for this server build: 27I'll start by listing all the components I used for this server build:
28 28
29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount 29- **Case**: [Rosewill RSV-R4100U 4U Server Chassis Rackmount
30 Case](https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825) 30 Case](https://www.rosewill.com/rosewill-rsv-r4100u-black/p/9SIA072GJ92825)
31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550) 31- **Motherboard**: [NZXT B550](https://nzxt.com/product/n7-b550)
32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics 32- **CPU**: AMD Ryzen 7 5700G with Radeon Graphics
33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that support 33- **GPU**: N/A - I specifically chose one of the few AMD CPUs that support
34 onboard graphics. 34 onboard graphics.
35- **RAM**: 64GB RAM (2x32GB) *Max of 128GB RAM on this motherboard* 35- **RAM**: 64GB RAM (2x32GB) _Max of 128GB RAM on this motherboard_
36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD 36- **Boot Drive**: Western Digital 500GB M.2 NVME SSD
37- **HDD Bay**: 37- **HDD Bay**:
38 - 10TB WD White *(shucked, moved from previous server)* 38 - 10TB WD White _(shucked, moved from previous server)_
39 - 8TB WD White *(shucked, moved from previous server)* 39 - 8TB WD White _(shucked, moved from previous server)_
40 - 2 x 8TB WD Red Plus *(Black Friday lined up perfectly with this build, 40 - 2 x 8TB WD Red Plus _(Black Friday lined up perfectly with this build,
41 so I grabbed two of these)* 41 so I grabbed two of these)_
42- **PSU**: Corsair RM850 PSU 42- **PSU**: Corsair RM850 PSU
43- **Extras**: 43- **Extras**:
44 - Corsair TM3Q Thermal Paste 44 - Corsair TM3Q Thermal Paste
45 - Noctua 120mm fan *(replacement for front case fan)* 45 - Noctua 120mm fan _(replacement for front case fan)_
46 - 2 x Noctua 80mm fans *(replacement for rear case fans)* 46 - 2 x Noctua 80mm fans _(replacement for rear case fans)_
47 - CableMatters 6Gbps SATA Cables 47 - CableMatters 6Gbps SATA Cables
48 48
49# Building the Server 49# Building the Server
50 50
@@ -70,8 +70,8 @@ with the tedium of removing the cage to install new drives.
70 70
71# Software 71# Software
72 72
73I'm not going to dive into the software as I have done so in other recent 73I'm not going to dive into the software as I have done so in other recent posts.
74posts. However, I wanted to note that I am using Alpine Linux on this server and 74However, I wanted to note that I am using Alpine Linux on this server and
75hosting most services inside Docker. No virtual machines (VMs) and very few 75hosting most services inside Docker. No virtual machines (VMs) and very few
76bare-metal services. 76bare-metal services.
77 77
content/blog/2022-11-29-nginx-referrer-ban-list.md +13 −10
@@ -20,7 +20,7 @@ doas nano /etc/nginx/banlist.conf
20Next, paste the following contents in and fill out the regexes with whichever 20Next, paste the following contents in and fill out the regexes with whichever
21domains you're blocking. 21domains you're blocking.
22 22
23``` conf 23```conf
24# /etc/nginx/banlist.conf 24# /etc/nginx/banlist.conf
25 25
26map $http_referer $bad_referer { 26map $http_referer $bad_referer {
@@ -45,7 +45,7 @@ doas nano /etc/nginx/nginx.conf
45Within this file, find the `http` block and add your ban list file location to 45Within this file, find the `http` block and add your ban list file location to
46the end of the block. 46the end of the block.
47 47
48``` conf 48```conf
49# /etc/nginx/nginx.conf 49# /etc/nginx/nginx.conf
50 50
51http { 51http {
@@ -76,7 +76,7 @@ Code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) you want. Code
76403 (Forbidden) is logical in this case since you are preventing a client 76403 (Forbidden) is logical in this case since you are preventing a client
77connection due to a banned domain. 77connection due to a banned domain.
78 78
79``` conf 79```conf
80server { 80server {
81 ... 81 ...
82 82
@@ -108,7 +108,7 @@ curl https://cleberg.net
108 108
109The HTML contents of the page come back successfully: 109The HTML contents of the page come back successfully:
110 110
111``` html 111```html
112<!doctype html>...</html> 112<!doctype html>...</html>
113``` 113```
114 114
@@ -122,12 +122,15 @@ This time, I'm met with a 403 Forbidden response page. That means we are
122successful and any clients being referred from a banned domain will be met with 122successful and any clients being referred from a banned domain will be met with
123this same response code. 123this same response code.
124 124
125``` html 125```html
126<html> 126<html>
127<head><title>403 Forbidden</title></head> 127 <head>
128<body> 128 <title>403 Forbidden</title>
129<center><h1>403 Forbidden</h1></center> 129 </head>
130<hr><center>nginx</center> 130 <body>
131</body> 131 <center><h1>403 Forbidden</h1></center>
132 <hr />
133 <center>nginx</center>
134 </body>
132</html> 135</html>
133``` 136```
content/blog/2022-12-01-nginx-compression.md +23 −23
@@ -22,10 +22,10 @@ nano /etc/nginx/nginx.conf
22 22
23Within the `http` block, find the section that shows something like the block 23Within the `http` block, find the section that shows something like the block
24below. This is the default gzip configuration I found in my `nginx.conf` file on 24below. This is the default gzip configuration I found in my `nginx.conf` file on
25Alpine Linux 3.17. Yours may look slightly different, just make sure that 25Alpine Linux 3.17. Yours may look slightly different, just make sure that you're
26you're not creating any duplicate gzip options. 26not creating any duplicate gzip options.
27 27
28``` conf 28```conf
29# Enable gzipping of responses. 29# Enable gzipping of responses.
30#gzip on; 30#gzip on;
31 31
@@ -35,7 +35,7 @@ gzip_vary on;
35 35
36Remove the default gzip lines and replace them with the following: 36Remove the default gzip lines and replace them with the following:
37 37
38``` conf 38```conf
39# Enable gzipping of responses. 39# Enable gzipping of responses.
40gzip on; 40gzip on;
41gzip_vary on; 41gzip_vary on;
@@ -50,25 +50,25 @@ gzip_disable "MSIE [1-6]";
50Each of the lines above enables a different aspect of the gzip response for 50Each of the lines above enables a different aspect of the gzip response for
51Nginx. Here are the full explanations: 51Nginx. Here are the full explanations:
52 52
53- `gzip` -- Enables or disables gzipping of responses. 53- `gzip` -- Enables or disables gzipping of responses.
54- `gzip_vary` -- Enables or disables inserting the "Vary: Accept-Encoding" 54- `gzip_vary` -- Enables or disables inserting the "Vary: Accept-Encoding"
55 response header field if the directives gzip, gzip~static~, or gunzip are 55 response header field if the directives gzip, gzip~static~, or gunzip are
56 active. 56 active.
57- `gzip_min_length` -- Sets the minimum length of a response that will be 57- `gzip_min_length` -- Sets the minimum length of a response that will be
58 gzipped. The length is determined only from the "Content-Length" response 58 gzipped. The length is determined only from the "Content-Length" response
59 header field. 59 header field.
60- `gzip_proxied` -- Enables or disables gzipping of responses for proxied 60- `gzip_proxied` -- Enables or disables gzipping of responses for proxied
61 requests depending on the request and response. The fact that the request is 61 requests depending on the request and response. The fact that the request is
62 proxied is determined by the presence of the "Via" request header field. 62 proxied is determined by the presence of the "Via" request header field.
63- `gzip_types` -- Enables gzipping of responses for the specified MIME types in 63- `gzip_types` -- Enables gzipping of responses for the specified MIME types
64 addition to "text/html". The special value "*" matches any MIME type 64 in addition to "text/html". The special value "\*" matches any MIME type
65 (0.8.29). Responses with the "text/html" type are always compressed. 65 (0.8.29). Responses with the "text/html" type are always compressed.
66- `gzip_disable` -- Disables gzipping of responses for requests with 66- `gzip_disable` -- Disables gzipping of responses for requests with
67 "User-Agent" header fields matching any of the specified regular 67 "User-Agent" header fields matching any of the specified regular
68 expressions. 68 expressions.
69 - The special mask "msie6" (0.7.12) corresponds to the regular expression 69 - The special mask "msie6" (0.7.12) corresponds to the regular expression
70 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE 70 "MSIE [4-6].", but works faster. Starting from version 0.8.11, "MSIE
71 6.0; ... SV1" is excluded from this mask. 71 6.0; ... SV1" is excluded from this mask.
72 72
73More information on these directives and their options can be found on the 73More information on these directives and their options can be found on the
74[Module 74[Module
content/blog/2022-12-07-nginx-wildcard-redirect.md +4 −4
@@ -20,7 +20,7 @@ Instead, I finally found a solution that allows me to redirect both subdomains
20AND trailing content. For example, both of these URLs now redirect properly 20AND trailing content. For example, both of these URLs now redirect properly
21using the logic I'll explain below: 21using the logic I'll explain below:
22 22
23``` txt 23```txt
24# Example 1 - Simple base domain redirect with trailing content 24# Example 1 - Simple base domain redirect with trailing content
25https://domain1.com/blog/alpine-linux/ -> https://domain2.com/blog/alpine-linux/ 25https://domain1.com/blog/alpine-linux/ -> https://domain2.com/blog/alpine-linux/
26 26
@@ -44,7 +44,7 @@ doas nano /etc/nginx/http.d/domain1.conf
44Within this file, I had one block configured to redirect HTTP requests to HTTPS 44Within this file, I had one block configured to redirect HTTP requests to HTTPS
45for the base domain and all subdomains. 45for the base domain and all subdomains.
46 46
47``` conf 47```conf
48server { 48server {
49 listen [::]:80; 49 listen [::]:80;
50 listen 80; 50 listen 80;
@@ -66,7 +66,7 @@ For the base domain, I have another `server` block dedicated to redirecting all
66base domain requests. You can see that the `rewrite` line is instructing Nginx 66base domain requests. You can see that the `rewrite` line is instructing Nginx
67to gather all trailing content and append it to the new `domain2.com` URL. 67to gather all trailing content and append it to the new `domain2.com` URL.
68 68
69``` conf 69```conf
70server { 70server {
71 listen [::]:443 ssl http2; 71 listen [::]:443 ssl http2;
72 listen 443 ssl http2; 72 listen 443 ssl http2;
@@ -91,7 +91,7 @@ Once the server gets to the `rewrite` line, it pulls the `subdomain` variable
91from above and uses it on the new `domain2.com` domain before appending the 91from above and uses it on the new `domain2.com` domain before appending the
92trailing content (`$request_uri`). 92trailing content (`$request_uri`).
93 93
94``` conf 94```conf
95server { 95server {
96 listen [::]:443 ssl http2; 96 listen [::]:443 ssl http2;
97 listen 443 ssl http2; 97 listen 443 ssl http2;
content/blog/2022-12-17-st.md +4 −4
@@ -57,8 +57,8 @@ Note that customizing `st` requires you to modify the source files or to
57download one of the [available patches](https://st.suckless.org/patches/) for 57download one of the [available patches](https://st.suckless.org/patches/) for
58suckless.org. 58suckless.org.
59 59
60If you've already installed `st` and want to customize or install a patch, 60If you've already installed `st` and want to customize or install a patch, start
61start by uninstalling the current program. 61by uninstalling the current program.
62 62
63```sh 63```sh
64cd ~/suckless/st 64cd ~/suckless/st
@@ -75,8 +75,8 @@ wget https://st.suckless.org/patches/defaultfontsize/st-defaultfontsize-20210225
75``` 75```
76 76
77Once the file is downloaded inside the `st` folder, apply the patch and 77Once the file is downloaded inside the `st` folder, apply the patch and
78re-install the program. You may need to install the `patch` command if you 78re-install the program. You may need to install the `patch` command if you don't
79don't have it installed already (you should have installed it above). 79have it installed already (you should have installed it above).
80 80
81```sh 81```sh
82patch -i st-defaultfontsize-20210225-4ef0cbd.diff 82patch -i st-defaultfontsize-20210225-4ef0cbd.diff
content/blog/2022-12-23-alpine-desktop.md +4 −4
@@ -59,7 +59,7 @@ For v3.17, the `repositories` file should look like this:
59nano /etc/apk/repositories 59nano /etc/apk/repositories
60``` 60```
61 61
62``` conf 62```conf
63#/media/sda/apks 63#/media/sda/apks
64http://mirrors.gigenet.com/alpinelinux/v3.17/main 64http://mirrors.gigenet.com/alpinelinux/v3.17/main
65http://mirrors.gigenet.com/alpinelinux/v3.17/community 65http://mirrors.gigenet.com/alpinelinux/v3.17/community
@@ -193,7 +193,7 @@ Then, I added the Wi-Fi entry to the bottom of the networking interface file:
193nano /etc/network/interfaces 193nano /etc/network/interfaces
194``` 194```
195 195
196``` conf 196```conf
197auto wlan0 197auto wlan0
198iface wlan0 inet dhcp 198iface wlan0 inet dhcp
199``` 199```
@@ -215,7 +215,7 @@ Really, the solution was to enable the `NameResolvingService=resolvconf` in
215doas nano /etc/iwd/main.conf 215doas nano /etc/iwd/main.conf
216``` 216```
217 217
218``` conf 218```conf
219[Network] 219[Network]
220 220
221NameResolvingService=resolvconf 221NameResolvingService=resolvconf
@@ -248,7 +248,7 @@ sway.
248nano ~/.config/sway/config 248nano ~/.config/sway/config
249``` 249```
250 250
251``` conf 251```conf
252# Run pipewire audio server 252# Run pipewire audio server
253exec /usr/libexec/pipewire-launcher 253exec /usr/libexec/pipewire-launcher
254 254
content/blog/2023-01-05-mass-unlike-tumblr-posts.md +20 −16
@@ -26,14 +26,18 @@ buttons.
26Tumblr's unlike buttons are structured as you can see in the following code 26Tumblr's unlike buttons are structured as you can see in the following code
27block. All unlike buttons have an `aria-label` with a value of `Unlike`. 27block. All unlike buttons have an `aria-label` with a value of `Unlike`.
28 28
29``` html 29```html
30<button class="TRX6J" aria-label="Unlike"> 30<button class="TRX6J" aria-label="Unlike">
31 <span class="EvhBA B1Z5w ztpfZ" tabindex="-1"> 31 <span class="EvhBA B1Z5w ztpfZ" tabindex="-1">
32 <svg xmlns="http://www.w3.org/2000/svg" height="21" width="23" 32 <svg
33 role="presentation"> 33 xmlns="http://www.w3.org/2000/svg"
34 <use href="#managed-icon__like-filled"></use> 34 height="21"
35 </svg> 35 width="23"
36 </span> 36 role="presentation"
37 >
38 <use href="#managed-icon__like-filled"></use>
39 </svg>
40 </span>
37</button> 41</button>
38``` 42```
39 43
@@ -46,8 +50,8 @@ Further, be sure to scroll down to the bottom and force Tumblr to load more
46posts so that this script unlikes more posts at a time. 50posts so that this script unlikes more posts at a time.
47 51
48Once you are logged in and the page is loaded, open the Developer Tools and be 52Once you are logged in and the page is loaded, open the Developer Tools and be
49sure you're on the "Console" tab. It should look something like this (this is 53sure you're on the "Console" tab. It should look something like this (this is in
50in Firefox, Chromium should be similar): 54Firefox, Chromium should be similar):
51 55
52![Firefox Dev 56![Firefox Dev
53!Tools](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/dev_console.png) 57!Tools](https:///img.cleberg.net/blog/20230105-mass-unlike-tumblr-posts/dev_console.png)
@@ -58,17 +62,17 @@ unlike it.
58 62
59Optionally, you can comment-out the line `elements[i].click();` and uncomment 63Optionally, you can comment-out the line `elements[i].click();` and uncomment
60the `console.log()` lines to simply print out information without performing any 64the `console.log()` lines to simply print out information without performing any
61actions. This can be useful to debug issues or confirm that the code below 65actions. This can be useful to debug issues or confirm that the code below isn't
62isn't doing anything you don't want it to. 66doing anything you don't want it to.
63 67
64``` javascript 68```javascript
65const elements = document.querySelectorAll('[aria-label="Unlike"]'); 69const elements = document.querySelectorAll('[aria-label="Unlike"]');
66// console.log(elements); // 👉 [button] 70// console.log(elements); // 👉 [button]
67 71
68for (let i=0; i < elements.length; i++) { 72for (let i = 0; i < elements.length; i++) {
69 // console.log(elements[i]); 73 // console.log(elements[i]);
70 elements[i].click(); 74 elements[i].click();
71} 75}
72``` 76```
73 77
74# Results 78# Results
content/blog/2023-01-08-fedora-login-manager.md +1 −1
@@ -33,7 +33,7 @@ In order to launch i3 manually, you need to set up your X session properly. To
33start, create or edit the `~/.xinitrc` file to include the following at the 33start, create or edit the `~/.xinitrc` file to include the following at the
34bottom. 34bottom.
35 35
36``` config 36```config
37exec i3 37exec i3
38``` 38```
39 39
content/blog/2023-01-21-flatpak-symlinks.md +3 −4
@@ -14,8 +14,8 @@ and manually running the Flatpak app with the lengthy `flatpak run ...` command.
14In the past, I manually created aliases in my `.zshrc` file for certain apps. 14In the past, I manually created aliases in my `.zshrc` file for certain apps.
15For example, an alias would look like the example below. 15For example, an alias would look like the example below.
16 16
17This would allow me to run the command fast within the terminal, but it 17This would allow me to run the command fast within the terminal, but it wouldn't
18wouldn't allow me to run it in an application launcher. 18allow me to run it in an application launcher.
19 19
20```sh 20```sh
21# ~/.zshrc 21# ~/.zshrc
@@ -27,8 +27,7 @@ tiling WMs I use and their application launchers - `dmenu` and `bemenu`.
27 27
28# Creating Symlinks for Flatpak Apps 28# Creating Symlinks for Flatpak Apps
29 29
30Let's use the example of Librewolf below. I can install the application like 30Let's use the example of Librewolf below. I can install the application like so:
31so:
32 31
33```sh 32```sh
34flatpak install flathub io.gitlab.librewolf-community 33flatpak install flathub io.gitlab.librewolf-community
content/blog/2023-01-23-random-wireguard.md +7 −7
@@ -7,8 +7,8 @@ draft = false
7 7
8# Mullvad Wireguard 8# Mullvad Wireguard
9 9
10If you're using an OS that does not support one of Mullvad's apps, you're 10If you're using an OS that does not support one of Mullvad's apps, you're likely
11likely using the Wireguard configuration files instead. 11using the Wireguard configuration files instead.
12 12
13If not, the first step is to visit Mullvad's [Wireguard configuration 13If not, the first step is to visit Mullvad's [Wireguard configuration
14files](https://mullvad.net/en/account/#/wireguard-config) page and download a 14files](https://mullvad.net/en/account/#/wireguard-config) page and download a
@@ -64,7 +64,7 @@ chmod +x ~/vpn.sh
64 64
65The output should look like the following: 65The output should look like the following:
66 66
67``` txt 67```txt
68doas (user@host) password: 68doas (user@host) password:
69 69
70# ... The script will process all of the iptables and wg commands here 70# ... The script will process all of the iptables and wg commands here
@@ -75,8 +75,8 @@ Printing new IP info:
75You are connected to Mullvad (server country-city-wg-num). Your IP address is 12.345.678.99 75You are connected to Mullvad (server country-city-wg-num). Your IP address is 12.345.678.99
76``` 76```
77 77
78That's all there is to it. You can see your new location and IP via the 78That's all there is to it. You can see your new location and IP via the `printf`
79`printf` and `curl` commands included in the script. 79and `curl` commands included in the script.
80 80
81You can also go to the [Connection Check ​\| 81You can also go to the [Connection Check ​\|
82Mullvad](https://mullvad.net/en/check/) page to see if you are fully connected 82Mullvad](https://mullvad.net/en/check/) page to see if you are fully connected
@@ -104,8 +104,8 @@ wg-quick down /home/user/mullvad/us-lax-wg-104.conf
104``` 104```
105 105
106I have a TODO item on figuring out how to easily export an environment variable 106I have a TODO item on figuring out how to easily export an environment variable
107that contains the configuration file's full name, so that I can just execute 107that contains the configuration file's full name, so that I can just execute the
108the following: 108following:
109 109
110```sh 110```sh
111# Ideal situation if I can export the $file variable to the environment 111# Ideal situation if I can export the $file variable to the environment
content/blog/2023-01-28-self-hosting-wger.md +26 −26
@@ -18,29 +18,29 @@ own after installing wger:
18 18
191. Dashboard 191. Dashboard
20 20
21 - Dashboard view of Workout Schedule, Nutrition Plan, Weight Graph, & last 21 - Dashboard view of Workout Schedule, Nutrition Plan, Weight Graph, & last
22 5 Weight Logs 22 5 Weight Logs
23 23
242. Training 242. Training
25 25
26 - Workout Log 26 - Workout Log
27 - Workout Schedule 27 - Workout Schedule
28 - Calendar (shows weight logs and Bad/Neutral/Good days) 28 - Calendar (shows weight logs and Bad/Neutral/Good days)
29 - Gallery (shows images you upload) 29 - Gallery (shows images you upload)
30 - Workout templates 30 - Workout templates
31 - Public templates 31 - Public templates
32 - Exercises 32 - Exercises
33 33
343. Nutrition 343. Nutrition
35 35
36 - Nutrition plans 36 - Nutrition plans
37 - BMI calculator 37 - BMI calculator
38 - Daily calories calculator 38 - Daily calories calculator
39 - Ingredient overview 39 - Ingredient overview
40 40
414. Body Weight 414. Body Weight
42 42
43 - Weight overview 43 - Weight overview
44 44
45## Documentation 45## Documentation
46 46
@@ -67,14 +67,14 @@ above.
67 67
68A few notes to explain the changes I made to the default files: 68A few notes to explain the changes I made to the default files:
69 69
70- I updated the `ALLOW_REGISTRAION` variable in `prod.env` to `False` after I 70- I updated the `ALLOW_REGISTRAION` variable in `prod.env` to `False` after I
71 created an account via my LAN connection, **before** I connected this app to a 71 created an account via my LAN connection, **before** I connected this app to
72 publicly-available domain. 72 a publicly-available domain.
73- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be equal to the public 73- I uncommented and updated `CSRF_TRUSTED_ORIGINS` to be equal to the public
74 version of this app: `https://wger.example.com`. 74 version of this app: `https://wger.example.com`.
75- I updated the port within `docker-compose.yml`, within the `nginx` block. The 75- I updated the port within `docker-compose.yml`, within the `nginx` block.
76 port I updated this to will be reflected in my nginx configuration file on the 76 The port I updated this to will be reflected in my nginx configuration file
77 server (NOT the wger nginx.conf file). 77 on the server (NOT the wger nginx.conf file).
78 78
79## Deploy 79## Deploy
80 80
@@ -89,17 +89,17 @@ You can now visit the website on your LAN by going to `localhost:YOUR_PORT` or
89by the server's IP, if you're not on the same machine that is running the 89by the server's IP, if you're not on the same machine that is running the
90container. 90container.
91 91
92If you wish to connect this app to a public domain name, you'll need to point 92If you wish to connect this app to a public domain name, you'll need to point an
93an `A` DNS record from the domain to your server's public IP. You'll then need 93`A` DNS record from the domain to your server's public IP. You'll then need to
94to create a configuration file for whichever web server or reverse proxy you're 94create a configuration file for whichever web server or reverse proxy you're
95using. 95using.
96 96
97Wger's README suggests the following reverse proxy configuration for Nginx: 97Wger's README suggests the following reverse proxy configuration for Nginx:
98 98
99``` conf 99```conf
100upstream wger { 100upstream wger {
101 # This port should match the port in the `nginx` block of docker-compose.yml 101 # This port should match the port in the `nginx` block of docker-compose.yml
102 # If the container is running on this same machine, replace this with 102 # If the container is running on this same machine, replace this with
103 # server 127.0.0.1:8080 103 # server 127.0.0.1:8080
104 server 123.456.789.0:8080; 104 server 123.456.789.0:8080;
105} 105}
content/blog/2023-02-02-exploring-hare.md +6 −6
@@ -33,8 +33,8 @@ program.
33 33
34## Installation 34## Installation
35 35
36I'm currently running Alpine Linux on my Thinkpad, so the installation was 36I'm currently running Alpine Linux on my Thinkpad, so the installation was quite
37quite easy as there is a package for Hare in the `apk` repositories. 37easy as there is a package for Hare in the `apk` repositories.
38 38
39```sh 39```sh
40doas apk add hare hare-doc 40doas apk add hare hare-doc
@@ -132,8 +132,8 @@ hare build -o example file.ha
132 132
133 While I was able to piece everything together eventually, the biggest 133 While I was able to piece everything together eventually, the biggest
134 downfall right now in Hare's documentation. For such a new project, the 134 downfall right now in Hare's documentation. For such a new project, the
135 documentation is in a great spot. However, bare specifications don't help 135 documentation is in a great spot. However, bare specifications don't help as
136 as much as a brief examples section would. 136 much as a brief examples section would.
137 137
138 For example, it took me a while to figure out what the `u64n` function was 138 For example, it took me a while to figure out what the `u64n` function was
139 looking for. I could tell that it took two parameters and the second was my 139 looking for. I could tell that it took two parameters and the second was my
@@ -150,8 +150,8 @@ hare build -o example file.ha
150 enjoy seeing in Hare, such as one to convert decimal (base 10) values to 150 enjoy seeing in Hare, such as one to convert decimal (base 10) values to
151 hexadecimal (base 16). 151 hexadecimal (base 16).
152 152
153 If I'm feeling comfortable with my math, I may work on the list of 153 If I'm feeling comfortable with my math, I may work on the list of functions
154 functions I want and see if any can make it into the Hare source code. 154 I want and see if any can make it into the Hare source code.
155 155
1563. Overall Thoughts 1563. Overall Thoughts
157 157
content/blog/2023-05-22-burnout.md +3 −3
@@ -5,7 +5,7 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8# RE: Burnout {#re-burnout-1} 8# RE: Burnout
9 9
10I recently read [Drew DeVault's post on 10I recently read [Drew DeVault's post on
11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html) around the 11burnout](https://drewdevault.com/2023/05/01/2023-05-01-Burnout.html) around the
@@ -41,5 +41,5 @@ programming, athletics, games, etc.
41You may have noticed my absence if you're in the same channels, forums, and 41You may have noticed my absence if you're in the same channels, forums, and
42rooms that I am, but I should finally be active again. 42rooms that I am, but I should finally be active again.
43 43
44I'm hoping to break an item out of my backlog soon and start working on 44I'm hoping to break an item out of my backlog soon and start working on building
45building a new project or hack around with a stale one. 45a new project or hack around with a stale one.
content/blog/2023-06-08-goaccess-geoip.md +1 −1
@@ -8,7 +8,7 @@ draft = false
8# Overview 8# Overview
9 9
10[GoAccess](https://goaccess.io/) is an open source real-time web log analyzer 10[GoAccess](https://goaccess.io/) is an open source real-time web log analyzer
11and interactive viewer that runs in a terminal in *nix systems or through your 11and interactive viewer that runs in a terminal in \*nix systems or through your
12browser. 12browser.
13 13
14# Installation 14# Installation
content/blog/2023-06-08-self-hosting-baikal.md +3 −3
@@ -28,14 +28,14 @@ the `ports` section to use any port on your server to pass through to port 80 in
28the container. You can also edit the `volumes` section to use docker volumes 28the container. You can also edit the `volumes` section to use docker volumes
29instead of local folders. 29instead of local folders.
30 30
31``` conf 31```conf
32version: "2" 32version: "2"
33services: 33services:
34 baikal: 34 baikal:
35 image: ckulka/baikal:nginx 35 image: ckulka/baikal:nginx
36 restart: always 36 restart: always
37 ports: 37 ports:
38 - "8567:80" 38 - "8567:80"
39 volumes: 39 volumes:
40 - ./config:/var/www/baikal/config 40 - ./config:/var/www/baikal/config
41 - ./data:/var/www/baikal/Specific 41 - ./data:/var/www/baikal/Specific
@@ -93,7 +93,7 @@ nano dav
93Within this file, paste in the configuration from below and change 93Within this file, paste in the configuration from below and change
94`dav.example.com` to match the URL you'll be using. 94`dav.example.com` to match the URL you'll be using.
95 95
96``` conf 96```conf
97server { 97server {
98 if ($host ~ ^[^.]+\.example\.com$) { 98 if ($host ~ ^[^.]+\.example\.com$) {
99 return 301 https://$host$request_uri; 99 return 301 https://$host$request_uri;
content/blog/2023-06-18-unifi-ip-blocklist.md +9 −8
@@ -7,8 +7,8 @@ draft = false
7 7
8# Identifying Abusive IPs 8# Identifying Abusive IPs
9 9
10If you're like me and use Unifi network equipment at the edge of the network 10If you're like me and use Unifi network equipment at the edge of the network you
11you manage, you may know that Unifi is only somewhat decent at identifying and 11manage, you may know that Unifi is only somewhat decent at identifying and
12blocking IPs that represent abusive or threat actors. 12blocking IPs that represent abusive or threat actors.
13 13
14While Unifi has a [threat 14While Unifi has a [threat
@@ -28,6 +28,7 @@ blocked yet.
28# Create an IP Group Profile 28# Create an IP Group Profile
29 29
30To start, login to the Unifi machine's web GUI and navigate to the Network app 30To start, login to the Unifi machine's web GUI and navigate to the Network app
31
31> Settings > Profiles. 32> Settings > Profiles.
32 33
33Within this page, choose the `IP Groups` tab and click `Create New`. 34Within this page, choose the `IP Groups` tab and click `Create New`.
@@ -58,12 +59,12 @@ navigate to the Network app > Settings > Firewall & Security.
58Within this screen, find the Firewall Rules table and click `Create Entry`. This 59Within this screen, find the Firewall Rules table and click `Create Entry`. This
59entry should contain the following settings: 60entry should contain the following settings:
60 61
61- Type: `Internet In` 62- Type: `Internet In`
62- Description: `<Your Custom Rule>` 63- Description: `<Your Custom Rule>`
63- Rule Applied: `Before Predefined Rules` 64- Rule Applied: `Before Predefined Rules`
64- Action: `Drop` 65- Action: `Drop`
65- Source Type: `Port/IP Group` 66- Source Type: `Port/IP Group`
66- IPv4 Address Group: `<Name of the Group Profile You Created Above>` 67- IPv4 Address Group: `<Name of the Group Profile You Created Above>`
67 68
68Customize the remaining configurations to your liking, and then save and enable 69Customize the remaining configurations to your liking, and then save and enable
69the firewall rule. 70the firewall rule.
content/blog/2023-06-20-audit-review-template.md +28 −27
@@ -7,7 +7,7 @@ draft = false
7 7
8# Overview 8# Overview
9 9
10This post is a *very* brief overview on the basic process to review audit test 10This post is a _very_ brief overview on the basic process to review audit test
11results, focusing on work done as part of a financial statement audit (FSA) or 11results, focusing on work done as part of a financial statement audit (FSA) or
12service organization controls (SOC) report. 12service organization controls (SOC) report.
13 13
@@ -25,52 +25,53 @@ variety of engagements, while still ensuring that all key areas are covered.
251. [ ] Check all documents for spelling and grammar. 251. [ ] Check all documents for spelling and grammar.
262. [ ] Ensure all acronyms are fully explained upon first use. 262. [ ] Ensure all acronyms are fully explained upon first use.
273. [ ] For all people referenced, use their full names and job titles upon first 273. [ ] For all people referenced, use their full names and job titles upon first
28 use. 28 use.
294. [ ] All supporting documents must cross-reference to the lead sheet and 294. [ ] All supporting documents must cross-reference to the lead sheet and
30 vice-versa. 30 vice-versa.
315. [ ] Verify that the control has been adequately tested: 315. [ ] Verify that the control has been adequately tested:
32 - [ ] **Test of Design**: Did the tester obtain information regarding how 32 - [ ] **Test of Design**: Did the tester obtain information regarding how
33 the control should perform normally and abnormally (e.g., emergency 33 the control should perform normally and abnormally (e.g., emergency
34 scenarios)? 34 scenarios)?
35 - [ ] **Test of Operating Effectiveness**: Did the tester inquire, observe, 35 - [ ] **Test of Operating Effectiveness**: Did the tester inquire, observe,
36 inspect, or re-perform sufficient evidence to support their conclusion 36 inspect, or re-perform sufficient evidence to support their conclusion
37 over the control? Inquiry alone is not adequate! 37 over the control? Inquiry alone is not adequate!
386. [ ] For any information used in the control, whether by the control operator 386. [ ] For any information used in the control, whether by the control operator
39 or by the tester, did the tester appropriately document the source (system or 39 or by the tester, did the tester appropriately document the source
40 person), extraction method, parameters, and completeness and accuracy (C&A)? 40 (system or person), extraction method, parameters, and completeness and
41 accuracy (C&A)?
41 - [ ] For any reports, queries, etc. used in the extraction, did the tester 42 - [ ] For any reports, queries, etc. used in the extraction, did the tester
42 include a copy and notate C&A considerations? 43 include a copy and notate C&A considerations?
437. [ ] Did the tester document the specific criteria that the control is being 447. [ ] Did the tester document the specific criteria that the control is being
44 tested against? 45 tested against?
458. [ ] Did the tester notate in the supporting documents where each criterion 468. [ ] Did the tester notate in the supporting documents where each criterion
46 was satisfied? 47 was satisfied?
479. [ ] If testing specific policies or procedures, are the documents adequate? 489. [ ] If testing specific policies or procedures, are the documents adequate?
48 - [ ] e.g., a test to validate that a review of policy XYZ occurs 49 - [ ] e.g., a test to validate that a review of policy XYZ occurs
49 periodically should also evaluate the sufficiency of the policy itself, if 50 periodically should also evaluate the sufficiency of the policy
50 meant to cover the risk that such a policy does not exist and is not 51 itself, if meant to cover the risk that such a policy does not exist
51 reviewed. 52 and is not reviewed.
5210. [ ] Does the test cover the appropriate period under review? 5310. [ ] Does the test cover the appropriate period under review?
53 - [ ] If the test is meant to cover only a portion of the audit period, do 54 - [ ] If the test is meant to cover only a portion of the audit period, do
54 other controls exist to mitigate the risks that exist for the remainder of 55 other controls exist to mitigate the risks that exist for the
55 the period? 56 remainder of the period?
5611. [ ] For any computer-aided audit tools (CAATs) or other automation 5711. [ ] For any computer-aided audit tools (CAATs) or other automation
57 techniques used in the test, is the use of such tools explained and 58 techniques used in the test, is the use of such tools explained and
58 appropriately documented? 59 appropriately documented?
5912. [ ] If prior-period documentation exists, are there any missing pieces of 6012. [ ] If prior-period documentation exists, are there any missing pieces of
60 evidence that would further enhance the quality of the test? 61 evidence that would further enhance the quality of the test?
6113. [ ] Was any information discovered during the walkthrough or inquiry phase 6213. [ ] Was any information discovered during the walkthrough or inquiry phase
62 that was not incorporated into the test? 63 that was not incorporated into the test?
6314. [ ] Are there new rules or expectations from your company's internal 6414. [ ] Are there new rules or expectations from your company's internal
64 guidance or your regulatory bodies that would affect the audit approach for 65 guidance or your regulatory bodies that would affect the audit approach
65 this control? 66 for this control?
6615. [ ] Was an exception, finding, or deficiency identified as a result of this 6715. [ ] Was an exception, finding, or deficiency identified as a result of this
67 test? 68 test?
68 - [ ] Was the control deficient in design, operation, or both? 69 - [ ] Was the control deficient in design, operation, or both?
69 - [ ] What was the root cause of the finding? 70 - [ ] What was the root cause of the finding?
70 - [ ] Does the finding indicate other findings or potential fraud? 71 - [ ] Does the finding indicate other findings or potential fraud?
71 - [ ] What's the severity and scope of the finding? 72 - [ ] What's the severity and scope of the finding?
72 - [ ] Do other controls exist as a form of compensation against the 73 - [ ] Do other controls exist as a form of compensation against the
73 finding's severity, and do they mitigate the risk within the control 74 finding's severity, and do they mitigate the risk within the control
74 objective? 75 objective?
75 - [ ] Does the finding exist at the end of the period, or was it resolved 76 - [ ] Does the finding exist at the end of the period, or was it resolved
76 within the audit period? 77 within the audit period?
content/blog/2023-06-23-byobu.md +2 −2
@@ -38,8 +38,8 @@ explore should be the keybindings section.
38 38
39The keybindings are configured as follows: 39The keybindings are configured as follows:
40 40
41``` txt 41```txt
42byobu keybindings can be user defined in /usr/share/byobu/keybindings/ (or 42byobu keybindings can be user defined in /usr/share/byobu/keybindings/ (or
43within .screenrc if byobu-export was used). The common key bindings are: 43within .screenrc if byobu-export was used). The common key bindings are:
44 44
45F2 - Create a new window 45F2 - Create a new window
content/blog/2023-06-23-self-hosting-convos.md +15 −15
@@ -10,15 +10,15 @@ draft = false
10[Convos](https://convos.chat/) is an always-online web client for IRC. It has a 10[Convos](https://convos.chat/) is an always-online web client for IRC. It has a
11few features that made it attractive to me as a self-hosted option: 11few features that made it attractive to me as a self-hosted option:
12 12
13- Extremely simple Docker Compose installation method. 13- Extremely simple Docker Compose installation method.
14- Runs in the background and monitors chats even while you're not logged in. 14- Runs in the background and monitors chats even while you're not logged in.
15- Neatly organized sidebar for conversation and client settings. 15- Neatly organized sidebar for conversation and client settings.
16- Ability to connect to different hosts and create profiles for hosts. 16- Ability to connect to different hosts and create profiles for hosts.
17- By default, registration is closed to the public. You can enable public 17- By default, registration is closed to the public. You can enable public
18 registration on the Settings page or generate invitation links on the Users 18 registration on the Settings page or generate invitation links on the Users
19 page. 19 page.
20- Customization of the client theme, organization name and URL, admin email, and 20- Customization of the client theme, organization name and URL, admin email,
21 video service. 21 and video service.
22 22
23# Docker Installation 23# Docker Installation
24 24
@@ -34,7 +34,7 @@ file. You can customize the host port to be something unique, such as
34`21897:3000`. You can also change the `data` folder to be a docker volume 34`21897:3000`. You can also change the `data` folder to be a docker volume
35instead, if you prefer. 35instead, if you prefer.
36 36
37``` config 37```config
38version: '3' 38version: '3'
39 39
40services: 40services:
@@ -71,7 +71,7 @@ Within the nginx configuration file, paste the following content and be sure to
71update `convos.example.com` to match your domain and `127.0.0.1:3000` to match 71update `convos.example.com` to match your domain and `127.0.0.1:3000` to match
72the port you opened in the `docker-compose.yml` file. 72the port you opened in the `docker-compose.yml` file.
73 73
74``` config 74```config
75# Host and port where convos is running 75# Host and port where convos is running
76upstream convos_upstream { server 127.0.0.1:3000; } 76upstream convos_upstream { server 127.0.0.1:3000; }
77 77
@@ -138,22 +138,22 @@ Convos, the default sever is libera.chat. Simply click the `libera` conversation
138at the top of the sidebar to open it. Once the chat is open, you can claim a 138at the top of the sidebar to open it. Once the chat is open, you can claim a
139nickname by typing: 139nickname by typing:
140 140
141``` txt 141```txt
142/nick <nick> 142/nick <nick>
143``` 143```
144 144
145If the nickname is available, and you'd like to register the nickname to 145If the nickname is available, and you'd like to register the nickname to
146yourself, you'll need to type another command: 146yourself, you'll need to type another command:
147 147
148``` txt 148```txt
149/msg NickServ REGISTER 149/msg NickServ REGISTER
150<password> <email> 150<password> <email>
151``` 151```
152 152
153On libera.chat, the server will send a confirmation email with a command that 153On libera.chat, the server will send a confirmation email with a command that
154you must message in IRC to verify registration of the nickname: 154you must message in IRC to verify registration of the nickname:
155 155
156``` txt 156```txt
157/msg NickServ VERIFY REGISTER <nick> <verification_code> 157/msg NickServ VERIFY REGISTER <nick> <verification_code>
158``` 158```
159 159
content/blog/2023-06-28-backblaze-b2.md +14 −14
@@ -15,11 +15,11 @@ $0.01/GB/month.
15 15
16However, there are free tiers: 16However, there are free tiers:
17 17
18- The first 10 GB of storage is free. 18- The first 10 GB of storage is free.
19- The first 1 GB of data downloaded each day is free. 19- The first 1 GB of data downloaded each day is free.
20- Class A transactions are free. 20- Class A transactions are free.
21- The first 2500 Class B transactions each day are free. 21- The first 2500 Class B transactions each day are free.
22- The first 2500 Class C transactions each day are free. 22- The first 2500 Class C transactions each day are free.
23 23
24You can see which API calls fall into categories A, B, or C here: [Pricing 24You can see which API calls fall into categories A, B, or C here: [Pricing
25Organized by API 25Organized by API
@@ -42,8 +42,8 @@ file upload and then sync an entire directory to my Backblaze bucket.
42# Create a Bucket 42# Create a Bucket
43 43
44Before you can start uploading, you need to create a bucket. If you're familiar 44Before you can start uploading, you need to create a bucket. If you're familiar
45with other object storage services, this will feel familiar. If not, it's 45with other object storage services, this will feel familiar. If not, it's pretty
46pretty simple to create one. 46simple to create one.
47 47
48As their webpage says: 48As their webpage says:
49 49
@@ -55,10 +55,10 @@ As their webpage says:
55Once you click the `Create a Bucket` button on their webpage or mobile app, you 55Once you click the `Create a Bucket` button on their webpage or mobile app, you
56need to provide the following: 56need to provide the following:
57 57
58- Bucket Unique Name 58- Bucket Unique Name
59- Files in Bucket are: `Private` or `Public` 59- Files in Bucket are: `Private` or `Public`
60- Default Encryption: `Disable` or `Enable` 60- Default Encryption: `Disable` or `Enable`
61- Object Lock: `Disable` or `Enable` 61- Object Lock: `Disable` or `Enable`
62 62
63For my bucket, I created a private bucket with encryption enabled and object 63For my bucket, I created a private bucket with encryption enabled and object
64lock disabled. 64lock disabled.
@@ -126,7 +126,7 @@ bucket:
126b2 ls <bucket_name> 126b2 ls <bucket_name>
127``` 127```
128 128
129``` txt 129```txt
130test.md 130test.md
131``` 131```
132 132
@@ -166,8 +166,8 @@ Note that symlinks are resolved by b2, so if you have a link from
166has 10TB of data, `b2` will resolve that link and start uploading all 10TB of 166has 10TB of data, `b2` will resolve that link and start uploading all 10TB of
167data linked within the folder. 167data linked within the folder.
168 168
169If you're not sure if you have any symlinks, a symlink will look like this 169If you're not sure if you have any symlinks, a symlink will look like this (note
170(note the `->` symbol): 170the `->` symbol):
171 171
172```sh 172```sh
173> ls -lha 173> ls -lha
content/blog/2023-06-30-self-hosting-voyager.md +4 −4
@@ -48,7 +48,7 @@ I will be using a `docker-compose.yml` file to run this container, instead of a
48nano docker-compose.yml 48nano docker-compose.yml
49``` 49```
50 50
51``` conf 51```conf
52version: "2" 52version: "2"
53services: 53services:
54 voyager: 54 voyager:
@@ -70,8 +70,8 @@ The web app will now be available at the following address:
70 70
71## Reverse Proxy 71## Reverse Proxy
72 72
73If you want to visit this app via an external URL or domain name, you'll need 73If you want to visit this app via an external URL or domain name, you'll need to
74to set up a reverse proxy. The example below uses Nginx as a reverse proxy. 74set up a reverse proxy. The example below uses Nginx as a reverse proxy.
75 75
76Simply create the configuration file, paste the contents below, save the file, 76Simply create the configuration file, paste the contents below, save the file,
77symlink the file, and restart Nginx. 77symlink the file, and restart Nginx.
@@ -80,7 +80,7 @@ symlink the file, and restart Nginx.
80sudo nano /etc/nginx/sites-available/voyager 80sudo nano /etc/nginx/sites-available/voyager
81``` 81```
82 82
83``` conf 83```conf
84server { 84server {
85 if ($host ~ ^[^.]+\.example\.com$) { 85 if ($host ~ ^[^.]+\.example\.com$) {
86 return 301 https://$host$request_uri; 86 return 301 https://$host$request_uri;
content/blog/2023-07-12-wireguard-lan.md +12 −12
@@ -25,7 +25,7 @@ doas mv *.conf /etc/wireguard/
25 25
26The default configuration files will look something like this: 26The default configuration files will look something like this:
27 27
28``` conf 28```conf
29[Interface] 29[Interface]
30# Device: <redacted> 30# Device: <redacted>
31PrivateKey = <redacted> 31PrivateKey = <redacted>
@@ -40,9 +40,9 @@ AllowedIPs = <redacted>
40Endpoint = <redacted> 40Endpoint = <redacted>
41``` 41```
42 42
43> Note: If you didn't select the kill switch option, you won't see the 43> Note: If you didn't select the kill switch option, you won't see the `PostUp`
44> `PostUp` and `PreDown` lines. In this case, you'll need to modify the script 44> and `PreDown` lines. In this case, you'll need to modify the script below to
45> below to simply append those lines to the `[Interface]` block. 45> simply append those lines to the `[Interface]` block.
46 46
47# Editing the Configuration Files 47# Editing the Configuration Files
48 48
@@ -51,15 +51,15 @@ Once you have the files, you'll need to edit them and replace the `PostUp` and
51 51
52I recommend that you do this process as root, since you'll need to be able to 52I recommend that you do this process as root, since you'll need to be able to
53access files in `/etc/wireguard`, which are generally owned by root. You can 53access files in `/etc/wireguard`, which are generally owned by root. You can
54also try using `sudo` or `doas`, but I didn't test that scenario so you may 54also try using `sudo` or `doas`, but I didn't test that scenario so you may need
55need to adjust, as necessary. 55to adjust, as necessary.
56 56
57```sh 57```sh
58su 58su
59``` 59```
60 60
61Create the Python file that we'll be using to update the Wireguard 61Create the Python file that we'll be using to update the Wireguard configuration
62configuration files. 62files.
63 63
64```sh 64```sh
65nano replace.py 65nano replace.py
@@ -73,7 +73,7 @@ commands.
73> Note: If your LAN is on a subnet other than `192.168.1.0/24`, you'll need to 73> Note: If your LAN is on a subnet other than `192.168.1.0/24`, you'll need to
74> update the Python script below appropriately. 74> update the Python script below appropriately.
75 75
76``` python 76```python
77import os 77import os
78import fileinput 78import fileinput
79 79
@@ -94,8 +94,8 @@ for file in os.listdir(dir):
94print("--- done ---") 94print("--- done ---")
95``` 95```
96 96
97Once you're done, save and close the file. You can now run the Python script 97Once you're done, save and close the file. You can now run the Python script and
98and watch as each file is updated. 98watch as each file is updated.
99 99
100```sh 100```sh
101python3 replace.py 101python3 replace.py
@@ -110,7 +110,7 @@ cat /etc/wireguard/us-chi-wg-001.conf
110 110
111The configuration files should now look like this: 111The configuration files should now look like this:
112 112
113``` conf 113```conf
114[Interface] 114[Interface]
115# Device: <redacted> 115# Device: <redacted>
116PrivateKey = <redacted> 116PrivateKey = <redacted>
content/blog/2023-07-19-plex-transcoder-errors.md +6 −6
@@ -10,21 +10,21 @@ draft = false
10Occasionally, you may see an error in your Plex client that references a failure 10Occasionally, you may see an error in your Plex client that references a failure
11with the transcoder conversion process. The specific error wording is: 11with the transcoder conversion process. The specific error wording is:
12 12
13``` txt 13```txt
14Conversion failed. The transcoder failed to start up. 14Conversion failed. The transcoder failed to start up.
15``` 15```
16 16
17# Debugging the Cause 17# Debugging the Cause
18 18
19In order to get a better look at what is causing the error, I'm going to 19In order to get a better look at what is causing the error, I'm going to observe
20observe the Plex console while the error occurs. To do this, open the Plex web 20the Plex console while the error occurs. To do this, open the Plex web client,
21client, go to `Settings` > `Manage` > `Console`. Now, try to play the title 21go to `Settings` > `Manage` > `Console`. Now, try to play the title again and
22again and watch to see which errors occur. 22watch to see which errors occur.
23 23
24In my case, you can see the errors below are related to a subtitle file (`.srt`) 24In my case, you can see the errors below are related to a subtitle file (`.srt`)
25causing the transcoder to crash. 25causing the transcoder to crash.
26 26
27``` txt 27```txt
28Jul 19, 2023 16:49:34.945 [140184571120440] Error — Couldn't find the file to stream: /movies/Movie Title (2021)/Movie Title (2021).srt 28Jul 19, 2023 16:49:34.945 [140184571120440] Error — Couldn't find the file to stream: /movies/Movie Title (2021)/Movie Title (2021).srt
29Jul 19, 2023 16:49:34.947 [140184532732728] Error — [Req#7611/Transcode/42935159-67C1-4192-9336-DDC6F7BC9330] Error configuring transcoder: TPU: Failed to download sub-stream to temporary file 29Jul 19, 2023 16:49:34.947 [140184532732728] Error — [Req#7611/Transcode/42935159-67C1-4192-9336-DDC6F7BC9330] Error configuring transcoder: TPU: Failed to download sub-stream to temporary file
30Jul 19, 2023 16:49:35.225 [140184532732728] Warning — [Req#760d/Transcode] Got a request to stop a transcode session without a valid session GUID. 30Jul 19, 2023 16:49:35.225 [140184532732728] Warning — [Req#760d/Transcode] Got a request to stop a transcode session without a valid session GUID.
content/blog/2023-08-18-agile-auditing.md +17 −17
@@ -52,20 +52,20 @@ processes and controls at hand.
52 52
53Audit Examples: 53Audit Examples:
54 54
55- Engagement teams must value the team members, client contacts, and their 55- Engagement teams must value the team members, client contacts, and their
56 interactions over the historical processes and tools that have been used. 56 interactions over the historical processes and tools that have been used.
57- Engagement teams must value a final report that contains sufficient audit 57- Engagement teams must value a final report that contains sufficient audit
58 documentation over excessive documentation or scope creep. 58 documentation over excessive documentation or scope creep.
59- Engagement teams must collaborate with the audit clients as much as feasible 59- Engagement teams must collaborate with the audit clients as much as feasible
60 to ensure that both sides are constantly updated with current knowledge of the 60 to ensure that both sides are constantly updated with current knowledge of
61 engagement's status and any potential findings, rather than waiting for 61 the engagement's status and any potential findings, rather than waiting for
62 pre-set meetings or the end of the engagement to communicate. 62 pre-set meetings or the end of the engagement to communicate.
63- Engagement teams must be able to respond to change in an engagement's 63- Engagement teams must be able to respond to change in an engagement's
64 schedule, scope, or environment to ensure that the project is completed in a 64 schedule, scope, or environment to ensure that the project is completed in a
65 timely manner and that all relevant areas are tested. 65 timely manner and that all relevant areas are tested.
66 - In terms of an audit department's portfolio, they must be able to respond 66 - In terms of an audit department's portfolio, they must be able to
67 to changes in their company's or client's environment and be able to 67 respond to changes in their company's or client's environment and be
68 dynamically change their audit plan accordingly. 68 able to dynamically change their audit plan accordingly.
69 69
70# Scrum 70# Scrum
71 71
@@ -74,9 +74,9 @@ how an audit team can potentially mold that mindset into the audit world, but
74how does a team implement these ideas? 74how does a team implement these ideas?
75 75
76There are many methods that use an Agile mindset, but I prefer 76There are many methods that use an Agile mindset, but I prefer
77[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)). Scrum is a 77[Scrum](<https://en.wikipedia.org/wiki/Scrum_(software_development)>). Scrum is
78framework based on Agile that enables a team to work through a project through a 78a framework based on Agile that enables a team to work through a project through
79series of roles, ceremonies, artifacts, and values. 79a series of roles, ceremonies, artifacts, and values.
80 80
81Let's dive into each of these individually. 81Let's dive into each of these individually.
82 82
content/blog/2023-09-15-self-hosting-gitweb.md +1 −1
@@ -34,7 +34,7 @@ Once installed, create an Nginx configuration file.
34sudo nano /etc/nginx/sites-available/git.example.com 34sudo nano /etc/nginx/sites-available/git.example.com
35``` 35```
36 36
37``` conf 37```conf
38server { 38server {
39 listen 80; 39 listen 80;
40 server_name example.com; 40 server_name example.com;
content/blog/2023-09-19-audit-sql-scripts.md +52 −52
@@ -18,7 +18,7 @@ types: Oracle, Microsoft SQL, and MySQL.
18You can use the following SQL script to see all users and their privileges in an 18You can use the following SQL script to see all users and their privileges in an
19Oracle database: 19Oracle database:
20 20
21``` sql 21```sql
22SELECT 22SELECT
23 grantee AS "User", 23 grantee AS "User",
24 privilege AS "Privilege" 24 privilege AS "Privilege"
@@ -52,11 +52,11 @@ You can also extract each table's information separately and perform processing
52outside the database to explore and determine the information necessary for the 52outside the database to explore and determine the information necessary for the
53audit: 53audit:
54 54
55``` sql 55```sql
56SELECT ** FROM sys.dba_role_privs; 56SELECT ** FROM sys.dba_role_privs;
57SELECT ** FROM sys.dba_sys_privs; 57SELECT ** FROM sys.dba_sys_privs;
58SELECT ** FROM sys.dba_tab_privs; 58SELECT ** FROM sys.dba_tab_privs;
59SELECT ** FROM sys.dba_users; 59SELECT ** FROM sys.dba_users;
60``` 60```
61 61
62# Microsoft SQL 62# Microsoft SQL
@@ -64,16 +64,16 @@ SELECT ** FROM sys.dba_users;
64You can use the following SQL script to see all users and their privileges in a 64You can use the following SQL script to see all users and their privileges in a
65Microsoft SQL Server database ([source](https://stackoverflow.com/a/30040784)): 65Microsoft SQL Server database ([source](https://stackoverflow.com/a/30040784)):
66 66
67``` sql 67```sql
68/* 68/*
69Security Audit Report 69Security Audit Report
701) List all access provisioned to a sql user or windows user/group directly 701) List all access provisioned to a sql user or windows user/group directly
712) List all access provisioned to a sql user or windows user/group through a database or application role 712) List all access provisioned to a sql user or windows user/group through a database or application role
723) List all access provisioned to the public role 723) List all access provisioned to the public role
73 73
74Columns Returned: 74Columns Returned:
75UserName : SQL or Windows/Active Directory user account. This could also be an Active Directory group. 75UserName : SQL or Windows/Active Directory user account. This could also be an Active Directory group.
76UserType : Value will be either 'SQL User' or 'Windows User'. This reflects the type of user defined for the 76UserType : Value will be either 'SQL User' or 'Windows User'. This reflects the type of user defined for the
77 SQL Server user account. 77 SQL Server user account.
78DatabaseUserName: Name of the associated user as defined in the database user account. The database user may not be the 78DatabaseUserName: Name of the associated user as defined in the database user account. The database user may not be the
79 same as the server user. 79 same as the server user.
@@ -86,70 +86,70 @@ PermissionType : Type of permissions the user/role has on an object. Examples c
86PermissionState : Reflects the state of the permission type, examples could include GRANT, DENY, etc. 86PermissionState : Reflects the state of the permission type, examples could include GRANT, DENY, etc.
87 This value may not be populated for all roles. Some built in roles have implicit permission 87 This value may not be populated for all roles. Some built in roles have implicit permission
88 definitions. 88 definitions.
89ObjectType : Type of object the user/role is assigned permissions on. Examples could include USER_TABLE, 89ObjectType : Type of object the user/role is assigned permissions on. Examples could include USER_TABLE,
90 SQL_SCALAR_FUNCTION, SQL_INLINE_TABLE_VALUED_FUNCTION, SQL_STORED_PROCEDURE, VIEW, etc. 90 SQL_SCALAR_FUNCTION, SQL_INLINE_TABLE_VALUED_FUNCTION, SQL_STORED_PROCEDURE, VIEW, etc.
91 This value may not be populated for all roles. Some built in roles have implicit permission 91 This value may not be populated for all roles. Some built in roles have implicit permission
92 definitions. 92 definitions.
93ObjectName : Name of the object that the user/role is assigned permissions on. 93ObjectName : Name of the object that the user/role is assigned permissions on.
94 This value may not be populated for all roles. Some built in roles have implicit permission 94 This value may not be populated for all roles. Some built in roles have implicit permission
95 definitions. 95 definitions.
96ColumnName : Name of the column of the object that the user/role is assigned permissions on. This value 96ColumnName : Name of the column of the object that the user/role is assigned permissions on. This value
97 is only populated if the object is a table, view or a table value function. 97 is only populated if the object is a table, view or a table value function.
98*/ 98*/
99 99
100--List all access provisioned to a sql user or windows user/group directly 100--List all access provisioned to a sql user or windows user/group directly
101SELECT 101SELECT
102 [UserName] = CASE princ.[type] 102 [UserName] = CASE princ.[type]
103 WHEN 'S' THEN princ.[name] 103 WHEN 'S' THEN princ.[name]
104 WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI 104 WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
105 END, 105 END,
106 [UserType] = CASE princ.[type] 106 [UserType] = CASE princ.[type]
107 WHEN 'S' THEN 'SQL User' 107 WHEN 'S' THEN 'SQL User'
108 WHEN 'U' THEN 'Windows User' 108 WHEN 'U' THEN 'Windows User'
109 END, 109 END,
110 [DatabaseUserName] = princ.[name], 110 [DatabaseUserName] = princ.[name],
111 [Role] = null, 111 [Role] = null,
112 [PermissionType] = perm.[permission_name], 112 [PermissionType] = perm.[permission_name],
113 [PermissionState] = perm.[state_desc], 113 [PermissionState] = perm.[state_desc],
114 [ObjectType] = obj.type_desc,--perm.[class_desc], 114 [ObjectType] = obj.type_desc,--perm.[class_desc],
115 [ObjectName] = OBJECT_NAME(perm.major_id), 115 [ObjectName] = OBJECT_NAME(perm.major_id),
116 [ColumnName] = col.[name] 116 [ColumnName] = col.[name]
117FROM 117FROM
118 --database user 118 --database user
119 sys.database_principals princ 119 sys.database_principals princ
120LEFT JOIN 120LEFT JOIN
121 --Login accounts 121 --Login accounts
122 sys.login_token ulogin on princ.[sid] = ulogin.[sid] 122 sys.login_token ulogin on princ.[sid] = ulogin.[sid]
123LEFT JOIN 123LEFT JOIN
124 --Permissions 124 --Permissions
125 sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id] 125 sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id]
126LEFT JOIN 126LEFT JOIN
127 --Table columns 127 --Table columns
128 sys.columns col ON col.[object_id] = perm.major_id 128 sys.columns col ON col.[object_id] = perm.major_id
129 AND col.[column_id] = perm.[minor_id] 129 AND col.[column_id] = perm.[minor_id]
130LEFT JOIN 130LEFT JOIN
131 sys.objects obj ON perm.[major_id] = obj.[object_id] 131 sys.objects obj ON perm.[major_id] = obj.[object_id]
132WHERE 132WHERE
133 princ.[type] in ('S','U') 133 princ.[type] in ('S','U')
134UNION 134UNION
135--List all access provisioned to a sql user or windows user/group through a database or application role 135--List all access provisioned to a sql user or windows user/group through a database or application role
136SELECT 136SELECT
137 [UserName] = CASE memberprinc.[type] 137 [UserName] = CASE memberprinc.[type]
138 WHEN 'S' THEN memberprinc.[name] 138 WHEN 'S' THEN memberprinc.[name]
139 WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI 139 WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
140 END, 140 END,
141 [UserType] = CASE memberprinc.[type] 141 [UserType] = CASE memberprinc.[type]
142 WHEN 'S' THEN 'SQL User' 142 WHEN 'S' THEN 'SQL User'
143 WHEN 'U' THEN 'Windows User' 143 WHEN 'U' THEN 'Windows User'
144 END, 144 END,
145 [DatabaseUserName] = memberprinc.[name], 145 [DatabaseUserName] = memberprinc.[name],
146 [Role] = roleprinc.[name], 146 [Role] = roleprinc.[name],
147 [PermissionType] = perm.[permission_name], 147 [PermissionType] = perm.[permission_name],
148 [PermissionState] = perm.[state_desc], 148 [PermissionState] = perm.[state_desc],
149 [ObjectType] = obj.type_desc,--perm.[class_desc], 149 [ObjectType] = obj.type_desc,--perm.[class_desc],
150 [ObjectName] = OBJECT_NAME(perm.major_id), 150 [ObjectName] = OBJECT_NAME(perm.major_id),
151 [ColumnName] = col.[name] 151 [ColumnName] = col.[name]
152FROM 152FROM
153 --Role/member associations 153 --Role/member associations
154 sys.database_role_members members 154 sys.database_role_members members
155JOIN 155JOIN
@@ -161,39 +161,39 @@ JOIN
161LEFT JOIN 161LEFT JOIN
162 --Login accounts 162 --Login accounts
163 sys.login_token ulogin on memberprinc.[sid] = ulogin.[sid] 163 sys.login_token ulogin on memberprinc.[sid] = ulogin.[sid]
164LEFT JOIN 164LEFT JOIN
165 --Permissions 165 --Permissions
166 sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id] 166 sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
167LEFT JOIN 167LEFT JOIN
168 --Table columns 168 --Table columns
169 sys.columns col on col.[object_id] = perm.major_id 169 sys.columns col on col.[object_id] = perm.major_id
170 AND col.[column_id] = perm.[minor_id] 170 AND col.[column_id] = perm.[minor_id]
171LEFT JOIN 171LEFT JOIN
172 sys.objects obj ON perm.[major_id] = obj.[object_id] 172 sys.objects obj ON perm.[major_id] = obj.[object_id]
173UNION 173UNION
174--List all access provisioned to the public role, which everyone gets by default 174--List all access provisioned to the public role, which everyone gets by default
175SELECT 175SELECT
176 [UserName] = '{All Users}', 176 [UserName] = '{All Users}',
177 [UserType] = '{All Users}', 177 [UserType] = '{All Users}',
178 [DatabaseUserName] = '{All Users}', 178 [DatabaseUserName] = '{All Users}',
179 [Role] = roleprinc.[name], 179 [Role] = roleprinc.[name],
180 [PermissionType] = perm.[permission_name], 180 [PermissionType] = perm.[permission_name],
181 [PermissionState] = perm.[state_desc], 181 [PermissionState] = perm.[state_desc],
182 [ObjectType] = obj.type_desc,--perm.[class_desc], 182 [ObjectType] = obj.type_desc,--perm.[class_desc],
183 [ObjectName] = OBJECT_NAME(perm.major_id), 183 [ObjectName] = OBJECT_NAME(perm.major_id),
184 [ColumnName] = col.[name] 184 [ColumnName] = col.[name]
185FROM 185FROM
186 --Roles 186 --Roles
187 sys.database_principals roleprinc 187 sys.database_principals roleprinc
188LEFT JOIN 188LEFT JOIN
189 --Role permissions 189 --Role permissions
190 sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id] 190 sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
191LEFT JOIN 191LEFT JOIN
192 --Table columns 192 --Table columns
193 sys.columns col on col.[object_id] = perm.major_id 193 sys.columns col on col.[object_id] = perm.major_id
194 AND col.[column_id] = perm.[minor_id] 194 AND col.[column_id] = perm.[minor_id]
195JOIN 195JOIN
196 --All objects 196 --All objects
197 sys.objects obj ON obj.[object_id] = perm.[major_id] 197 sys.objects obj ON obj.[object_id] = perm.[major_id]
198WHERE 198WHERE
199 --Only roles 199 --Only roles
@@ -222,7 +222,7 @@ mysql -u root -p
222 222
223Find all users and hosts with access to the database: 223Find all users and hosts with access to the database:
224 224
225``` sql 225```sql
226SELECT ** FROM information_schema.user_privileges; 226SELECT ** FROM information_schema.user_privileges;
227``` 227```
228 228
@@ -243,7 +243,7 @@ after extraction. I have marked the queries below with `SELECT ...` and excluded
243most `WHERE` clauses for brevity. You should determine the relevant privileges 243most `WHERE` clauses for brevity. You should determine the relevant privileges
244in-scope and query for those privileges to reduce the length of time to query. 244in-scope and query for those privileges to reduce the length of time to query.
245 245
246``` sql 246```sql
247-- Global Permissions 247-- Global Permissions
248SELECT ... FROM mysql.user; 248SELECT ... FROM mysql.user;
249 249
@@ -260,6 +260,6 @@ SELECT ... FROM mysql.columns_priv
260WHERE db = @db_name; 260WHERE db = @db_name;
261 261
262-- Password Configuration 262-- Password Configuration
263SHOW GLOBAL VARIABLES LIKE 'validate_password%'; 263SHOW GLOBAL VARIABLES LIKE 'validate_password%';
264SHOW VARIABLES LIKE 'validate_password%'; 264SHOW VARIABLES LIKE 'validate_password%';
265``` 265```
content/blog/2023-10-04-digital-minimalism.md +49 −49
@@ -5,9 +5,9 @@ description = ""
5draft = false 5draft = false
6+++ 6+++
7 7
8I've written [a note about minimalism](file:///wiki/#digital-garden) before, 8I've written [a note about minimalism](file:///wiki/#digital-garden) before, but
9but I wanted to dedicate some time to reflect on digital minimalism and how 9I wanted to dedicate some time to reflect on digital minimalism and how I've
10I've been able to minimize the impact of digital devices in my life. 10been able to minimize the impact of digital devices in my life.
11 11
12> These changes crept up on us and happened fast, before we had a chance to step 12> These changes crept up on us and happened fast, before we had a chance to step
13> back and ask what we really wanted out of the rapid advances of the past 13> back and ask what we really wanted out of the rapid advances of the past
@@ -16,29 +16,29 @@ I've been able to minimize the impact of digital devices in my life.
16> our daily life. We didn't, in other words, sign up for the digital world in 16> our daily life. We didn't, in other words, sign up for the digital world in
17> which we're currently entrenched; we seem to have stumbled backward into it. 17> which we're currently entrenched; we seem to have stumbled backward into it.
18> 18>
19> *(Digital Minimalism, 2019)* 19> _(Digital Minimalism, 2019)_
20 20
21# The Principles of Digital Minimalism 21# The Principles of Digital Minimalism
22 22
23As noted in Cal Newport's book, *Digital Minimalism*, there are three main 23As noted in Cal Newport's book, _Digital Minimalism_, there are three main
24principles to digital minimalism that I tend to agree with: 24principles to digital minimalism that I tend to agree with:
25 25
261. Clutter is costly. 261. Clutter is costly.
27 - Digital minimalists recognize that cluttering their time and attention 27 - Digital minimalists recognize that cluttering their time and attention
28 with too many devices, apps, and services creates an overall negative cost 28 with too many devices, apps, and services creates an overall negative
29 that can swamp the small benefits that each individual item provides in 29 cost that can swamp the small benefits that each individual item
30 isolation. 30 provides in isolation.
312. Optimization is important. 312. Optimization is important.
32 - Digital minimalists believe that deciding a particular technology supports 32 - Digital minimalists believe that deciding a particular technology
33 something they value is only the first step. To truly extract its full 33 supports something they value is only the first step. To truly extract
34 potential benefit, it's necessary to think carefully about how they'll 34 its full potential benefit, it's necessary to think carefully about how
35 use the technology. 35 they'll use the technology.
363. Intentionality is satisfying. 363. Intentionality is satisfying.
37 - Digital minimalists derive significant satisfaction from their general 37 - Digital minimalists derive significant satisfaction from their general
38 commitment to being more intentional about how they engage with new 38 commitment to being more intentional about how they engage with new
39 technologies. This source of satisfaction is independent of the specific 39 technologies. This source of satisfaction is independent of the specific
40 decisions they make and is one of the biggest reasons that minimalism 40 decisions they make and is one of the biggest reasons that minimalism
41 tends to be immensely meaningful to its practitioners. 41 tends to be immensely meaningful to its practitioners.
42 42
43# Taking Action 43# Taking Action
44 44
@@ -47,47 +47,47 @@ continued performing old habits that are working well:
47 47
48## Using Devices With Intention 48## Using Devices With Intention
49 49
50- I already rarely use "social media", mostly limited to forums such as Hacker 50- I already rarely use "social media", mostly limited to forums such as Hacker
51 News and Tildes, so I've just tweaked my behavior to stop looking for content 51 News and Tildes, so I've just tweaked my behavior to stop looking for
52 in those places when I'm bored. 52 content in those places when I'm bored.
53- Use devices with intention. Each time I pick up a digital device, there should 53- Use devices with intention. Each time I pick up a digital device, there
54 be an intention to use the device to improve my current situation. No more 54 should be an intention to use the device to improve my current situation. No
55 endless scrolling or searching for something to interest me. 55 more endless scrolling or searching for something to interest me.
56 56
57## Prevent Distractions 57## Prevent Distractions
58 58
59- Disable (most) notifications on all devices. I spent 15-30 minutes going 59- Disable (most) notifications on all devices. I spent 15-30 minutes going
60 through the notifications on my phone, watch, and computer to ensure that only 60 through the notifications on my phone, watch, and computer to ensure that
61 a select few apps have the ability to interrupt me: Calendar, Messages, Phone, 61 only a select few apps have the ability to interrupt me: Calendar, Messages,
62 Reminders, & Signal. 62 Phone, Reminders, & Signal.
63- Disable badges for any apps except the ones mentioned in the bullet above. 63- Disable badges for any apps except the ones mentioned in the bullet above.
64- Set-up focus profiles across devices so that I can enable different modes, 64- Set-up focus profiles across devices so that I can enable different modes,
65 such as Personal when I only want to see notifications from people I care 65 such as Personal when I only want to see notifications from people I care
66 about or Do Not Disturb, where absolutely nothing can interrupt me. 66 about or Do Not Disturb, where absolutely nothing can interrupt me.
67- Clean up my home screens. This one was quite easy as I already maintain a 67- Clean up my home screens. This one was quite easy as I already maintain a
68 minimalist set-up, but I went extreme by limiting my phone to just eight apps 68 minimalist set-up, but I went extreme by limiting my phone to just eight
69 on the home screen and four in the dock. If I need another app, I'll have to 69 apps on the home screen and four in the dock. If I need another app, I'll
70 search or use the app library. 70 have to search or use the app library.
71- Remove the work profile from my phone. This was a tough decision as having my 71- Remove the work profile from my phone. This was a tough decision as having
72 work profile on my device definitely makes my life easier at times, but it 72 my work profile on my device definitely makes my life easier at times, but
73 also has quite a negative effect when I'm "always online" and can see the 73 it also has quite a negative effect when I'm "always online" and can see the
74 notifications and team activity 24/7. I believe creating a distinct barrier 74 notifications and team activity 24/7. I believe creating a distinct barrier
75 between my work and personal devices will be beneficial in the end. 75 between my work and personal devices will be beneficial in the end.
76 76
77## Creating Alternative Activities 77## Creating Alternative Activities
78 78
79This is the most difficult piece, as most of my hobbies and interests lie in the 79This is the most difficult piece, as most of my hobbies and interests lie in the
80digital world. However, I'm making a concerted effort to put devices down 80digital world. However, I'm making a concerted effort to put devices down unless
81unless necessary and force myself to perform other activities in the physical 81necessary and force myself to perform other activities in the physical world
82world instead. 82instead.
83 83
84I've started with a few basics that are always readily available to me: 84I've started with a few basics that are always readily available to me:
85 85
86- Do a chore, such as organizing or cleaning. 86- Do a chore, such as organizing or cleaning.
87- Read a book, study a piece of art, etc. 87- Read a book, study a piece of art, etc.
88- Exercise or get outdoors. 88- Exercise or get outdoors.
89- Participate in a hobby, such as photography, birding, disc golf, etc. 89- Participate in a hobby, such as photography, birding, disc golf, etc.
90- Let yourself be bored and wander into creativity. 90- Let yourself be bored and wander into creativity.
91 91
92# Making Progress 92# Making Progress
93 93
content/blog/2023-10-11-self-hosting-authelia.md +105 −105
@@ -23,11 +23,11 @@ portal.
23 23
24This guide assumes you have the following already set-up: 24This guide assumes you have the following already set-up:
25 25
26- A registered domain with DNS pointing to your server. 26- A registered domain with DNS pointing to your server.
27- A subdomain for Authelia (`auth.example.com`) and a subdomain to protect via 27- A subdomain for Authelia (`auth.example.com`) and a subdomain to protect via
28 Authelia (`app.example.com`). 28 Authelia (`app.example.com`).
29- A working Nginx web server. 29- A working Nginx web server.
30- Docker and docker-compose installed. 30- Docker and docker-compose installed.
31 31
32# Installation 32# Installation
33 33
@@ -49,19 +49,19 @@ Within this file, paste the following content. If you prefer a different local
49port, modify the port on the left side of the colon on the `9091:9091` line. Be 49port, modify the port on the left side of the colon on the `9091:9091` line. Be
50sure to modify the `TZ` variable to your timezone. 50sure to modify the `TZ` variable to your timezone.
51 51
52``` yml 52```yml
53version: '3.3' 53version: "3.3"
54 54
55services: 55services:
56 authelia: 56 authelia:
57 image: authelia/authelia 57 image: authelia/authelia
58 container_name: authelia 58 container_name: authelia
59 volumes: 59 volumes:
60 - ./config:/config 60 - ./config:/config
61 ports: 61 ports:
62 - 9091:9091 62 - 9091:9091
63 environment: 63 environment:
64 - TZ=America/Chicago 64 - TZ=America/Chicago
65``` 65```
66 66
67Start the container with docker-compose: 67Start the container with docker-compose:
@@ -93,107 +93,107 @@ and modify as necessary.
93 93
94The major required changes are: 94The major required changes are:
95 95
96- Any instances of `example.com` should be replaced by your domain. 96- Any instances of `example.com` should be replaced by your domain.
97- `jwt_secret` - Use the `pwgen 40 1` command to generate a secret for yourself. 97- `jwt_secret` - Use the `pwgen 40 1` command to generate a secret for
98- `access_control` - Set the Authelia domain to bypass here, as well as any 98 yourself.
99 subdomains you want to protect. 99- `access_control` - Set the Authelia domain to bypass here, as well as any
100- `session` > `secret` - Use the `pwgen 40 1` command to generate a secret for 100 subdomains you want to protect.
101 yourself. 101- `session` > `secret` - Use the `pwgen 40 1` command to generate a secret for
102- `regulation` - Set the variables here to restrict login attempts and bans. 102 yourself.
103- `storage` > `encryption_key` - Use the `pwgen 40 1` command to generate a 103- `regulation` - Set the variables here to restrict login attempts and bans.
104 secret for yourself. 104- `storage` > `encryption_key` - Use the `pwgen 40 1` command to generate a
105- `smtp` - If you have access to an SMTP service, set up the information here to 105 secret for yourself.
106 active outgoing emails. 106- `smtp` - If you have access to an SMTP service, set up the information here
107 107 to active outgoing emails.
108``` yml 108
109```yml
109# yamllint disable rule:comments-indentation 110# yamllint disable rule:comments-indentation
110--- 111---
111############################################################################### 112###############################################################################
112# Authelia Configuration # 113# Authelia Configuration #
113############################################################################### 114###############################################################################
114 115
115theme: dark 116theme: dark
116jwt_secret: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1 117jwt_secret: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1
117 118
118default_redirection_url: https://example.com 119default_redirection_url: https://example.com
119 120
120server: 121server:
121 host: 0.0.0.0 122 host: 0.0.0.0
122 port: 9091 123 port: 9091
123 path: "" 124 path: ""
124 read_buffer_size: 4096 125 read_buffer_size: 4096
125 write_buffer_size: 4096 126 write_buffer_size: 4096
126 enable_pprof: false 127 enable_pprof: false
127 enable_expvars: false 128 enable_expvars: false
128 disable_healthcheck: false 129 disable_healthcheck: false
129 tls: 130 tls:
130 key: "" 131 key: ""
131 certificate: "" 132 certificate: ""
132 133
133log: 134log:
134 level: debug 135 level: debug
135 136
136totp: 137totp:
137 issuer: example.com 138 issuer: example.com
138 period: 30 139 period: 30
139 skew: 1 140 skew: 1
140 141
141authentication_backend: 142authentication_backend:
142 disable_reset_password: false 143 disable_reset_password: false
143 refresh_interval: 5m 144 refresh_interval: 5m
144 file: 145 file:
145 path: /config/users_database.yml 146 path: /config/users_database.yml
146 password: 147 password:
147 algorithm: argon2id 148 algorithm: argon2id
148 iterations: 1 149 iterations: 1
149 key_length: 32 150 key_length: 32
150 salt_length: 16 151 salt_length: 16
151 memory: 1024 152 memory: 1024
152 parallelism: 8 153 parallelism: 8
153 154
154access_control: 155access_control:
155 default_policy: deny 156 default_policy: deny
156 rules: 157 rules:
157 - domain: 158 - domain:
158 - "auth.example.com" 159 - "auth.example.com"
159 policy: bypass 160 policy: bypass
160 - domain: "teddit.example.com" 161 - domain: "teddit.example.com"
161 policy: one_factor 162 policy: one_factor
162 163
163session: 164session:
164 name: authelia_session 165 name: authelia_session
165 secret: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1 166 secret: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1
166 expiration: 3600 167 expiration: 3600
167 inactivity: 300 168 inactivity: 300
168 domain: example.com 169 domain: example.com
169 170
170regulation: 171regulation:
171 max_retries: 5 172 max_retries: 5
172 find_time: 10m 173 find_time: 10m
173 ban_time: 12h 174 ban_time: 12h
174 175
175storage: 176storage:
176 local: 177 local:
177 path: /config/db.sqlite3 178 path: /config/db.sqlite3
178 encryption_key: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1 179 encryption_key: aiS5iedaiv6eeVaideeLeich5roo6ohvaf3Vee1a # pwgen 40 1
179 180
180notifier: 181notifier:
181 disable_startup_check: true 182 disable_startup_check: true
182 smtp: 183 smtp:
183 username: user@example.com 184 username: user@example.com
184 password: password 185 password: password
185 host: smtp.example.com 186 host: smtp.example.com
186 port: 465 187 port: 465
187 sender: user@example.com 188 sender: user@example.com
188 identifier: example.com 189 identifier: example.com
189 subject: "[Authelia] {title}" 190 subject: "[Authelia] {title}"
190 startup_check_address: user@example.com 191 startup_check_address: user@example.com
191 disable_require_tls: false 192 disable_require_tls: false
192 disable_html_emails: true 193 disable_html_emails: true
193 tls: 194 tls:
194 skip_verify: false 195 skip_verify: false
195 minimum_version: TLS1.2 196 minimum_version: TLS1.2
196...
197``` 197```
198 198
199## Authelia Users 199## Authelia Users
@@ -212,17 +212,17 @@ To generate the password, go to [Argon2 Hash Generator](https://argon2.online),
212generate a random salt, and make sure the rest of the settings match the 212generate a random salt, and make sure the rest of the settings match the
213`authentication_backend` section of `configuration.yml` file. 213`authentication_backend` section of `configuration.yml` file.
214 214
215``` yaml 215```yaml
216users: 216users:
217 my_username: 217 my_username:
218 displayname: "My User" 218 displayname: "My User"
219 # Generated at https://argon2.online/ -- match the settings in 219 # Generated at https://argon2.online/ -- match the settings in
220 # the `authentication_backend` section of configuration.yml 220 # the `authentication_backend` section of configuration.yml
221 password: "" 221 password: ""
222 email: email@example.com 222 email: email@example.com
223 groups: 223 groups:
224 - admins 224 - admins
225 - dev 225 - dev
226``` 226```
227 227
228Once the app is configured, restart the container from scratch. 228Once the app is configured, restart the container from scratch.
@@ -247,7 +247,7 @@ Within this file, paste the following information and be sure to update
247`example.com` to your domain. Make sure the `$upstream_authelia` variable 247`example.com` to your domain. Make sure the `$upstream_authelia` variable
248matches the location of your Authelia container. 248matches the location of your Authelia container.
249 249
250``` conf 250```conf
251server { 251server {
252 if ($host ~ ^[^.]+\.example\.com$) { 252 if ($host ~ ^[^.]+\.example\.com$) {
253 return 301 https://$host$request_uri; 253 return 301 https://$host$request_uri;
@@ -322,7 +322,7 @@ variables.
322sudo nano /etc/nginx/sites-available/teddit 322sudo nano /etc/nginx/sites-available/teddit
323``` 323```
324 324
325``` conf 325```conf
326server { 326server {
327 if ($host ~ ^[^.]+\.example\.com$) { 327 if ($host ~ ^[^.]+\.example\.com$) {
328 return 301 https://$host$request_uri; 328 return 301 https://$host$request_uri;
@@ -441,9 +441,9 @@ authentication domain and presented with the Authelia login portal.
441![Authelia 441![Authelia
442Portal](https://img.cleberg.net/blog/20231010-authelia/authelia_portal.png) 442Portal](https://img.cleberg.net/blog/20231010-authelia/authelia_portal.png)
443 443
444Once you've successfully authenticated, you can visit your authentication 444Once you've successfully authenticated, you can visit your authentication domain
445domain directly and see that you're currently authenticated to any domain 445directly and see that you're currently authenticated to any domain protected by
446protected by Authelia. 446Authelia.
447 447
448![Authelia 448![Authelia
449Success](https://img.cleberg.net/blog/20231010-authelia/authelia_success.png) 449Success](https://img.cleberg.net/blog/20231010-authelia/authelia_success.png)
content/blog/2023-10-15-alpine-ssh-hardening.md +1 −1
@@ -68,7 +68,7 @@ ssh-audit localhost
68If everything succeeded, the results will show as all green. If anything is 68If everything succeeded, the results will show as all green. If anything is
69yellow, orange, or red, you may need to tweak additional settings. 69yellow, orange, or red, you may need to tweak additional settings.
70 70
71``` txt 71```txt
72#+caption: ssh audit 72#+caption: ssh audit
73``` 73```
74 74
content/blog/2023-10-17-self-hosting-anonymousoverflow.md +7 −7
@@ -28,19 +28,19 @@ nano docker-compose.yml
28Within this file, paste the following information. Be sure to change the 28Within this file, paste the following information. Be sure to change the
29`APP_URL`, `JWT_SIGNING_SECRET`, and `ports` to match your needs. 29`APP_URL`, `JWT_SIGNING_SECRET`, and `ports` to match your needs.
30 30
31``` yaml 31```yaml
32version: '3' 32version: "3"
33 33
34services: 34services:
35 anonymousoverflow: 35 anonymousoverflow:
36 container_name: 'app' 36 container_name: "app"
37 image: 'ghcr.io/httpjamesm/anonymousoverflow:release' 37 image: "ghcr.io/httpjamesm/anonymousoverflow:release"
38 environment: 38 environment:
39 - APP_URL=https://ao.example.com 39 - APP_URL=https://ao.example.com
40 - JWT_SIGNING_SECRET=secret #pwgen 40 1 40 - JWT_SIGNING_SECRET=secret #pwgen 40 1
41 ports: 41 ports:
42 - '9380:8080' 42 - "9380:8080"
43 restart: 'always' 43 restart: "always"
44``` 44```
45 45
46Save and exit the file when complete. You can now launch the container and 46Save and exit the file when complete. You can now launch the container and
@@ -65,7 +65,7 @@ Within this file, paste the following content and repace `ao.example.com` with
65your URL. You may need to update the SSL certificate statements if your 65your URL. You may need to update the SSL certificate statements if your
66certificates are in a different location. 66certificates are in a different location.
67 67
68``` conf 68```conf
69server { 69server {
70 if ($host ~ ^[^.]+\.cleberg\.net$) { 70 if ($host ~ ^[^.]+\.cleberg\.net$) {
71 return 301 https://$host$request_uri; 71 return 301 https://$host$request_uri;
content/blog/2023-11-08-scli.md +14 −14
@@ -20,15 +20,15 @@ and download the packaged binaries for an easier installation process.
20 20
21In order to use `scli`, you need a few dependencies: 21In order to use `scli`, you need a few dependencies:
22 22
23- `openjdk17-jre` - Used as a dependency for the `signal-cli` tool. Version may 23- `openjdk17-jre` - Used as a dependency for the `signal-cli` tool. Version
24 vary. 24 may vary.
25- `signal-cli` - Used as the backbone of the `scli` tool. 25- `signal-cli` - Used as the backbone of the `scli` tool.
26- `findutils` - Replaces the standard Busybox version of `xargs`. 26- `findutils` - Replaces the standard Busybox version of `xargs`.
27- `urwid` - A console user interface library for Python. 27- `urwid` - A console user interface library for Python.
28- `urwid-readline` - For GNU emacs-like keybinds on the input line. 28- `urwid-readline` - For GNU emacs-like keybinds on the input line.
29- `qrencode` - Displays a QR code in the terminal to link the device using your 29- `qrencode` - Displays a QR code in the terminal to link the device using
30 phone. Not necessary if you're only linking on desktop and can copy/paste the 30 your phone. Not necessary if you're only linking on desktop and can
31 connection URL. 31 copy/paste the connection URL.
32 32
33Let's start by installing the packages available via Alpine's repositories. Be 33Let's start by installing the packages available via Alpine's repositories. Be
34sure to install the latest version of `openjdk`. If you run into Java-related 34sure to install the latest version of `openjdk`. If you run into Java-related
@@ -102,8 +102,8 @@ signal-cli -u USERNAME receive
102``` 102```
103 103
104Also be sure to test the daemon to ensure it works properly. If no errors occur, 104Also be sure to test the daemon to ensure it works properly. If no errors occur,
105it's working. If you run into errors because you're not running a DBUS 105it's working. If you run into errors because you're not running a DBUS session,
106session, see my notes below. 106see my notes below.
107 107
108```sh 108```sh
109signal-cli -u USERNAME daemon 109signal-cli -u USERNAME daemon
@@ -115,8 +115,8 @@ This process will differ depending on your desktop environment (DE). If you are
115running a DE, you likely have a DBUS session running already and can simply 115running a DE, you likely have a DBUS session running already and can simply
116launch the program. 116launch the program.
117 117
118However, if you're like me and running your computer straight on the TTY 118However, if you're like me and running your computer straight on the TTY without
119without a DE, you'll need to start a DBUS session for this program. 119a DE, you'll need to start a DBUS session for this program.
120 120
121```sh 121```sh
122# If you're not running a DBUS session yet, you need to start one for scli 122# If you're not running a DBUS session yet, you need to start one for scli
@@ -136,7 +136,7 @@ information on configuration options.
136nano ~/.config/sclirc 136nano ~/.config/sclirc
137``` 137```
138 138
139``` conf 139```conf
140# ~/.config/sclirc 140# ~/.config/sclirc
141 141
142wrap-at = 80 142wrap-at = 80
content/blog/2023-12-03-unifi-nextdns.md +6 −6
@@ -25,12 +25,12 @@ Install instructions for Unifi Dream Machine (UDM) standard and pro routers.
25 25
26Enable SSH: 26Enable SSH:
27 27
28- Go to your unifi admin interface and select your device (not the controller 28- Go to your unifi admin interface and select your device (not the controller
29 settings, but the Dream Machine settings) 29 settings, but the Dream Machine settings)
30- Click on "Settings" at the bottom of the page 30- Click on "Settings" at the bottom of the page
31- Go to the "Advanced" section on the left pan 31- Go to the "Advanced" section on the left pan
32- Enable SSH 32- Enable SSH
33- Set a SSH password 33- Set a SSH password
34 34
35Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with the password you 35Connect to your router using `ssh root@xxx.xxx.xxx.xxx` with the password you
36configured. 36configured.
content/blog/2024-01-08-dont-say-hello.md +4 −4
@@ -20,10 +20,10 @@ Therefore, I have always held a deep displeasure for conversations where people
20start with "Hello" and then. 20start with "Hello" and then.
21 21
22I searched back through my work messages and found that I received ~50 messages 22I searched back through my work messages and found that I received ~50 messages
23from ~10 people last year from people that contained "hi", "hey", or 23from ~10 people last year from people that contained "hi", "hey", or "hello" and
24"hello" and did not contain any indication of the purpose of the conversation. 24did not contain any indication of the purpose of the conversation. I also
25I also noticed that a few of the users were responsible for the large majority 25noticed that a few of the users were responsible for the large majority of the
26of the cliffhangers. 26cliffhangers.
27 27
28There's no real point to this post, just a desparate request for people to 28There's no real point to this post, just a desparate request for people to
29please stop doing this. 29please stop doing this.
content/blog/2024-01-09-macos-customization.md +4 −4
@@ -61,7 +61,7 @@ Integrity Protection (SIP). However, I chose not to do this and it hasn't
61affected my basic usage of yabai at all. 61affected my basic usage of yabai at all.
62 62
63Refer to the [yabai 63Refer to the [yabai
64wiki](https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)) 64wiki](<https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)>)
65for installation instructions. You will need to ensure that yabai is allowed to 65for installation instructions. You will need to ensure that yabai is allowed to
66access the accessibility and screen recording APIs. 66access the accessibility and screen recording APIs.
67 67
@@ -94,7 +94,7 @@ nano ~/.config/skhd/skhdrc
94 94
95For example, I have hotkeys to open my browser and terminal: 95For example, I have hotkeys to open my browser and terminal:
96 96
97``` conf 97```conf
98# Terminal 98# Terminal
99cmd - return : /Applications/iTerm.app/Contents/MacOS/iTerm2 99cmd - return : /Applications/iTerm.app/Contents/MacOS/iTerm2
100 100
@@ -159,8 +159,8 @@ them by following this process.
1592. Navigate to the `Applications` folder. 1592. Navigate to the `Applications` folder.
1603. Right-click an application of your choice, and select `Get Info`. 1603. Right-click an application of your choice, and select `Get Info`.
1614. Drag the image you downloaded on top of the application's icon at the top of 1614. Drag the image you downloaded on top of the application's icon at the top of
162 information window (you will see a green "plus" symbol when you're 162 information window (you will see a green "plus" symbol when you're hovering
163 hovering over it). 163 over it).
1645. Release the new icon on top of the old icon and it will update! 1645. Release the new icon on top of the old icon and it will update!
165 165
166You can see an example of me dragging a new `signal.icns` file onto my 166You can see an example of me dragging a new `signal.icns` file onto my
content/blog/2024-01-13-local-llm.md +12 −12
@@ -14,10 +14,10 @@ without sacrificing privacy or requiring in-depth technical setup.
14 14
15My requirements for this test: 15My requirements for this test:
16 16
17- Open source platform 17- Open source platform
18- On-device model files 18- On-device model files
19- Minimal required configuration 19- Minimal required configuration
20- Preferably pre-built, but a simple build process is acceptable 20- Preferably pre-built, but a simple build process is acceptable
21 21
22I tested a handful of apps and have summarized my favorite (so far) for macOS 22I tested a handful of apps and have summarized my favorite (so far) for macOS
23and iOS below. 23and iOS below.
@@ -25,8 +25,8 @@ and iOS below.
25> TL;DR - Here are the two that met my requirements and I have found the easiest 25> TL;DR - Here are the two that met my requirements and I have found the easiest
26> to install and use so far: 26> to install and use so far:
27 27
28- macOS: [Ollama](https://ollama.ai/) 28- macOS: [Ollama](https://ollama.ai/)
29- iOS : [LLM Farm](https://llmfarm.site/) 29- iOS : [LLM Farm](https://llmfarm.site/)
30 30
31# macOS 31# macOS
32 32
@@ -86,8 +86,8 @@ repository](https://github.com/guinmoon/LLMFarm) if you wish.
86The caveat is that you will have to manually download the model files from the 86The caveat is that you will have to manually download the model files from the
87links in the 87links in the
88[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md) file to 88[models.md](https://github.com/guinmoon/LLMFarm/blob/main/models.md) file to
89your iPhone to use the app - there's currently no option in the app to reach 89your iPhone to use the app - there's currently no option in the app to reach out
90out and grab the latest version of any supported model. 90and grab the latest version of any supported model.
91 91
92Once you have a file downloaded, you simply create a new chat and select the 92Once you have a file downloaded, you simply create a new chat and select the
93downloaded model file and ensure the inference matches the requirement in the 93downloaded model file and ensure the inference matches the requirement in the
@@ -96,10 +96,10 @@ downloaded model file and ensure the inference matches the requirement in the
96See below for a test of the ORCA Mini v3 model: 96See below for a test of the ORCA Mini v3 model:
97 97
98| Chat List | Chat | 98| Chat List | Chat |
99|-------------------------------------------------------------------------|-------------------------------------------------------------------| 99| ----------------------------------------------------------------------- | ----------------------------------------------------------------- |
100| ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) | ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png) | 100| ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm_chats.png) | ![](https://img.cleberg.net/blog/20240113-local-llm/llm_farm.png) |
101 101
102[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for private 102[Enchanted](https://github.com/AugustDev/enchanted) is also an iOS for private
103AI models, but it requires a public-facing Ollama API, which did not meet my 103AI models, but it requires a public-facing Ollama API, which did not meet my "on
104"on device requirement." Nonetheless, it's an interesting looking app and I 104device requirement." Nonetheless, it's an interesting looking app and I will
105will likely set it up to test soon. 105likely set it up to test soon.
content/blog/2024-01-26-audit-dashboard.md +48 −49
@@ -18,11 +18,11 @@ With these tools, we are going to build the following dashboard:
18 18
19This project assumes the following: 19This project assumes the following:
20 20
21- You have access to Alteryx Designer and Power BI Desktop. 21- You have access to Alteryx Designer and Power BI Desktop.
22 - If you only have Power BI Desktop, you may need to perform some analysis 22 - If you only have Power BI Desktop, you may need to perform some analysis
23 in Power BI instead of Alteryx. 23 in Power BI instead of Alteryx.
24- Your data is in a format that can be imported into Alteryx and/or Power BI. 24- Your data is in a format that can be imported into Alteryx and/or Power BI.
25- You have a basic understanding of data types and visualization. 25- You have a basic understanding of data types and visualization.
26 26
27# Alteryx: Data Preparation & Analysis 27# Alteryx: Data Preparation & Analysis
28 28
@@ -42,25 +42,24 @@ Import](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_import.png
42 42
43## Transform Data 43## Transform Data
44 44
45Next, let's replace null data and remove whitespace to clean up our data. We 45Next, let's replace null data and remove whitespace to clean up our data. We can
46can do this with the `Data Cleansing` tool in the `Preparation` tab in the 46do this with the `Data Cleansing` tool in the `Preparation` tab in the Ribbon.
47Ribbon.
48 47
49Ensure that the following options are enabled: 48Ensure that the following options are enabled:
50 49
51- Replace Nulls 50- Replace Nulls
52 - Replace with Blanks (String Fields) 51 - Replace with Blanks (String Fields)
53 - Replace with 0 (Numeric Fields) 52 - Replace with 0 (Numeric Fields)
54- Remove Unwanted Characters 53- Remove Unwanted Characters
55 - Leading and Trailing Whitespace 54 - Leading and Trailing Whitespace
56 55
57![Data 56![Data
58Cleansing](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_cleansing.png) 57Cleansing](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_cleansing.png)
59 58
60For our next step, we will transform the date fields from strings to datetime 59For our next step, we will transform the date fields from strings to datetime
61format. Add a `Datetime` tool for each field you want to transform - in the 60format. Add a `Datetime` tool for each field you want to transform - in the
62example below, I am using the tool twice for the "Started On" and "Submitted 61example below, I am using the tool twice for the "Started On" and "Submitted On"
63On" fields. 62fields.
64 63
65![Data 64![Data
66Transformation](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_transformation.png) 65Transformation](https://img.cleberg.net/blog/20240126-audit-dashboard/alteryx_transformation.png)
@@ -70,7 +69,7 @@ on those fields. Start by adding a `Filter` tool, naming a new Output Column,
70and pasting the formula below into it (the two fields used in this formula must 69and pasting the formula below into it (the two fields used in this formula must
71match the output of the `Datetime` tools above): 70match the output of the `Datetime` tools above):
72 71
73``` txt 72```txt
74DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days") 73DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days")
75``` 74```
76 75
@@ -93,8 +92,8 @@ To start, open the Power BI Desktop application. Upon first use, Power BI will
93ask if you want to open an existing dashboard or import new data. 92ask if you want to open an existing dashboard or import new data.
94 93
95As we are creating our first dashboard, let's import our data. In my example 94As we are creating our first dashboard, let's import our data. In my example
96below, I'm importing data from the "Tracker" sheet of the Excel file I'm 95below, I'm importing data from the "Tracker" sheet of the Excel file I'm using
97using for this project. 96for this project.
98 97
99During this process, I also imported the export from the Alteryx workflow above. 98During this process, I also imported the export from the Alteryx workflow above.
100Therefore, we have two different files available for use in our dashboard. 99Therefore, we have two different files available for use in our dashboard.
@@ -115,25 +114,25 @@ below and format as needed:
115 114
116Instructions to create the visuals above: 115Instructions to create the visuals above:
117 116
118- `Text Box`: Explain the name and purpose of the dashboard. You can also add 117- `Text Box`: Explain the name and purpose of the dashboard. You can also add
119 images and logos at the top of the dashboard. 118 images and logos at the top of the dashboard.
120- `Donut Chart`: Overall status of the project. 119- `Donut Chart`: Overall status of the project.
121 - `Legend`: Status 120 - `Legend`: Status
122 - `Values`: Count of Status 121 - `Values`: Count of Status
123- `Stacked Column Chart`: Task count by assignee. 122- `Stacked Column Chart`: Task count by assignee.
124 - `X-axis`: Preparer 123 - `X-axis`: Preparer
125 - `Y-axis`: Count of Control ID 124 - `Y-axis`: Count of Control ID
126 - `Legend`: Status 125 - `Legend`: Status
127- `Treemap`: Top N client submitters by average days to submit. 126- `Treemap`: Top N client submitters by average days to submit.
128 - `Details`: Preparer 127 - `Details`: Preparer
129 - `Values`: Sum of Avg~DaysToSubmit~ 128 - `Values`: Sum of Avg~DaysToSubmit~
130- `Line Chart`: Projected vs. actual hours over time. 129- `Line Chart`: Projected vs. actual hours over time.
131- `Clustered Bar Chart`: Projected vs. actual hours per person. 130- `Clustered Bar Chart`: Projected vs. actual hours per person.
132- `Slicer & Table` - Upcoming due dates. 131- `Slicer & Table` - Upcoming due dates.
133 - `Slicer`: 132 - `Slicer`:
134 - `Values`: Date Due 133 - `Values`: Date Due
135 - `Table`: 134 - `Table`:
136 - `Columns`: Count of Control ID, Date Due, Preparer, Status 135 - `Columns`: Count of Control ID, Date Due, Preparer, Status
137 136
138## Format the Dashboard 137## Format the Dashboard
139 138
@@ -144,18 +143,18 @@ created by your organization.
144For each visual, you can click the `Format` button in the `Visualizations` side 143For each visual, you can click the `Format` button in the `Visualizations` side
145pane and explore the options. You can custom options such as: 144pane and explore the options. You can custom options such as:
146 145
147- Visual 146- Visual
148 - Legend 147 - Legend
149 - Colors 148 - Colors
150 - Data labels 149 - Data labels
151 - Category labels 150 - Category labels
152- General 151- General
153 - Properties 152 - Properties
154 - Title 153 - Title
155 - Effects 154 - Effects
156 - Header icons 155 - Header icons
157 - Tooltips 156 - Tooltips
158 - Alt text 157 - Alt text
159 158
160You can always look online for inspiration when trying to decide how best to 159You can always look online for inspiration when trying to decide how best to
161organize and style your dashboard. 160organize and style your dashboard.
content/blog/2024-01-27-tableau-dashboard.md +7 −7
@@ -42,7 +42,7 @@ nano data_processing.py
42 42
43Within the Python script, paste the following: 43Within the Python script, paste the following:
44 44
45``` python 45```python
46# Import modules 46# Import modules
47import pandas as pd 47import pandas as pd
48import glob 48import glob
@@ -122,12 +122,12 @@ drag it into the `Columns` or `Rows` area of the canvas.
122See below for the map visualization. You can recreate this by adding the 122See below for the map visualization. You can recreate this by adding the
123following fields: 123following fields:
124 124
125- `Columns`: Lon 125- `Columns`: Lon
126- `Rows`: Lat 126- `Rows`: Lat
127- `Marks`: 127- `Marks`:
128 - Description 128 - Description
129 - Datetime 129 - Datetime
130- `Filters`: Datetime 130- `Filters`: Datetime
131 131
132![Worksheet 132![Worksheet
133Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/worksheet_edit.png) 133Editing](https://img.cleberg.net/blog/20240127-tableau-dashboard/worksheet_edit.png)
content/blog/2024-02-06-zfs.md +25 −24
@@ -10,10 +10,11 @@ snapshots on Ubuntu Server.
10 10
11I found the following pages very helpful while going through this process: 11I found the following pages very helpful while going through this process:
12 12
13- [Setup a ZFS storage 13- [Setup a ZFS storage
14 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool) 14 pool](https://ubuntu.com/tutorials/setup-zfs-storage-pool)
15- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS) 15- [Kernel/Reference/ZFS](https://wiki.ubuntu.com/Kernel/Reference/ZFS)
16- [ZFS for Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/) 16- [ZFS for
17 Dummies](https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/)
17 18
18# Installation 19# Installation
19 20
@@ -40,13 +41,13 @@ You have various options for configuring ZFS pools that all come different pros
40and cons. I suggest visiting the links at the top of this post or searching 41and cons. I suggest visiting the links at the top of this post or searching
41online for the best configuration for your use-case. 42online for the best configuration for your use-case.
42 43
43- Striped VDEVs (Raid0) 44- Striped VDEVs (Raid0)
44- Mirrored VDEVs (Raid1) 45- Mirrored VDEVs (Raid1)
45- Striped Mirrored VDEVs (Raid10) 46- Striped Mirrored VDEVs (Raid10)
46- RAIDz (Raid5) 47- RAIDz (Raid5)
47- RAIDz2 (Raidd6) 48- RAIDz2 (Raidd6)
48- RAIDz3 49- RAIDz3
49- Nested RAIDz (Raid50, Raid60) 50- Nested RAIDz (Raid50, Raid60)
50 51
51I will be using Raid10 in this guide. However, the majority of the steps are the 52I will be using Raid10 in this guide. However, the majority of the steps are the
52same regardless of your chosen pool configuration. 53same regardless of your chosen pool configuration.
@@ -84,8 +85,8 @@ sudo umount /dev/sda1
84sudo umount /dev/sdb1 85sudo umount /dev/sdb1
85``` 86```
86 87
87Now that I've identified the disks I want to use and have them unmounted, 88Now that I've identified the disks I want to use and have them unmounted, let's
88let's create the pool. For this example, I will call it `tank`. 89create the pool. For this example, I will call it `tank`.
89 90
90```sh 91```sh
91sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb 92sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb
@@ -176,10 +177,10 @@ command.
176See below for instructions on how to use `fdisk`. Here's what I did to create 177See below for instructions on how to use `fdisk`. Here's what I did to create
177basic Linux formatted disks: 178basic Linux formatted disks:
178 179
179- `g` : Create GPT partition table 180- `g` : Create GPT partition table
180- `n` : Create a new partition, hit Enter for all default options 181- `n` : Create a new partition, hit Enter for all default options
181- `t` : Change partition type to `20` for `Linux filesystem` 182- `t` : Change partition type to `20` for `Linux filesystem`
182- `w` : Write the changes to disk and exit 183- `w` : Write the changes to disk and exit
183 184
184I repeated this process for both disks. 185I repeated this process for both disks.
185 186
@@ -314,10 +315,10 @@ no datasets available
314 315
315# My Thoughts on ZFS So Far 316# My Thoughts on ZFS So Far
316 317
317- I sacrificed 25TB to be able to mirror my data, but I feel more comfortable 318- I sacrificed 25TB to be able to mirror my data, but I feel more comfortable
318 with the potential to save my data by quickly replacing a disk if I need to. 319 with the potential to save my data by quickly replacing a disk if I need to.
319- The set-up was surprisingly easy and fast. 320- The set-up was surprisingly easy and fast.
320- Disk I/O is fast as well. I was worried that the data transfer speeds would be 321- Disk I/O is fast as well. I was worried that the data transfer speeds would
321 slower due to the RAID configuration. 322 be slower due to the RAID configuration.
322- Media streaming and transcoding has seen no noticeable drop in performance. 323- Media streaming and transcoding has seen no noticeable drop in performance.
323- My only limitation really is the number of HDD bays in my server HDD cage. 324- My only limitation really is the number of HDD bays in my server HDD cage.
content/blog/2024-02-13-ubuntu-emergency-mode.md +3 −3
@@ -14,7 +14,7 @@ creating the ZFS pool.
14My server was stuck in the boot process and showed the following error on the 14My server was stuck in the boot process and showed the following error on the
15screen: 15screen:
16 16
17``` txt 17```txt
18You are in emergency mode. 18You are in emergency mode.
19After logging in, type "journalctl -xb" to view system logs, 19After logging in, type "journalctl -xb" to view system logs,
20"systemctl reboot" to reboot, "systemctl default" 20"systemctl reboot" to reboot, "systemctl default"
@@ -25,7 +25,7 @@ After rebooting the server and watching the logs scroll on a monitor, I noticed
25the root cause was related to a very long search for certain drives. I kept 25the root cause was related to a very long search for certain drives. I kept
26seeing errors like this: 26seeing errors like this:
27 27
28``` txt 28```txt
29[ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid] 29[ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid]
30``` 30```
31 31
@@ -49,7 +49,7 @@ Within the `fstab` file, I needed to comment/remove the following lines at the
49bottom of the file. You can comment-out a line by prepending a `#` symbol at the 49bottom of the file. You can comment-out a line by prepending a `#` symbol at the
50beginning of the line. You can also delete the line entirely. 50beginning of the line. You can also delete the line entirely.
51 51
52``` conf 52```conf
53# What it looked like when running into the issue: 53# What it looked like when running into the issue:
54UUID=B64E53824E5339F7 /mnt/white-01 ntfs-3g uid=1000,gid=1000 0 0 54UUID=B64E53824E5339F7 /mnt/white-01 ntfs-3g uid=1000,gid=1000 0 0
55UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0 55UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0
content/blog/2024-02-21-self-hosting-otter-wiki.md +5 −6
@@ -24,8 +24,7 @@ Start by creating a directory for the container's files.
24mkdir ~/otterwiki 24mkdir ~/otterwiki
25``` 25```
26 26
27Next, create the `docker-compose.yml` file to define the container's 27Next, create the `docker-compose.yml` file to define the container's parameters.
28parameters.
29 28
30```sh 29```sh
31nano ~/otterwiki/docker-compose.yml 30nano ~/otterwiki/docker-compose.yml
@@ -34,7 +33,7 @@ nano ~/otterwiki/docker-compose.yml
34Within the file, paste the following content. You can read the project's 33Within the file, paste the following content. You can read the project's
35documentation if you want to further override or customize the container. 34documentation if you want to further override or customize the container.
36 35
37``` conf 36```conf
38version: '3' 37version: '3'
39services: 38services:
40 otterwiki: 39 otterwiki:
@@ -72,7 +71,7 @@ have a TLS/SSL cert to use with this subdomain. If not, simply remove the
72`ssl_*` variables, remove the `80` server block, and change the `443` server 71`ssl_*` variables, remove the `80` server block, and change the `443` server
73block to `80` to serve the app without SSL. 72block to `80` to serve the app without SSL.
74 73
75``` conf 74```conf
76server { 75server {
77 if ($host ~ ^[^.]+\.example\.com$) { 76 if ($host ~ ^[^.]+\.example\.com$) {
78 return 301 https://$host$request_uri; 77 return 301 https://$host$request_uri;
@@ -129,8 +128,8 @@ Wiki. Start by creating your admin account and configure the app as necessary.
129![An Otter Wiki - Initial 128![An Otter Wiki - Initial
130Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki.png) 129Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki.png)
131 130
132You can also see the default editing screen for creating and editing pages. 131You can also see the default editing screen for creating and editing pages. It's
133It's as easy as typing Markdown and hitting the save button. 132as easy as typing Markdown and hitting the save button.
134 133
135![An Otter Wiki - Editing 134![An Otter Wiki - Editing
136Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki-edit.png) 135Screen](https://img.cleberg.net/blog/20240221-otterwiki/otterwiki-edit.png)
content/blog/2024-03-13-doom-emacs.md +8 −8
@@ -66,7 +66,7 @@ Once installed, you can configure Doom by editing the files within the
663. `init.el` - Doom modules and load order, must run `doom sync` after 663. `init.el` - Doom modules and load order, must run `doom sync` after
67 modifying 67 modifying
684. `packages.el` - Declare packages to install in this file, then run `doom 684. `packages.el` - Declare packages to install in this file, then run `doom
69 sync` to install 69sync` to install
70 70
71I only needed a few customizations for my configuration, so I'll list them 71I only needed a few customizations for my configuration, so I'll list them
72below. 72below.
@@ -167,7 +167,7 @@ changes, close files, and switch between open files. Here are some example
167shortcuts I've written down in order to accomplish file-based actions. 167shortcuts I've written down in order to accomplish file-based actions.
168 168
169| Doom Hotkey | Emacs Hotkey | Description | 169| Doom Hotkey | Emacs Hotkey | Description |
170|-----------------|--------------|----------------------------------------| 170| --------------- | ------------ | -------------------------------------- |
171| `SPC :` | `C-x` | Run functions | 171| `SPC :` | `C-x` | Run functions |
172| `SPC f f` | `C-x f` | Open file in buffer | 172| `SPC f f` | `C-x f` | Open file in buffer |
173| `SPC f d` | `C-x d` | Open directory with `dired` | 173| `SPC f d` | `C-x d` | Open directory with `dired` |
@@ -178,8 +178,8 @@ shortcuts I've written down in order to accomplish file-based actions.
178| `SPC w h/j/k/l` | `C-x o`[^1] | Move left/down/up/right to next buffer | 178| `SPC w h/j/k/l` | `C-x o`[^1] | Move left/down/up/right to next buffer |
179 179
180[^1]: Doom's evil-window functionality is a bit different from GNU Emacs, but 180[^1]: Doom's evil-window functionality is a bit different from GNU Emacs, but
181you can always switch to the "other" buffer with `C-x o` or `C-x b` to get a 181 you can always switch to the "other" buffer with `C-x o` or `C-x b` to get a
182list of buffers to select. 182 list of buffers to select.
183 183
184In general, when in Doom, you can press `SPC` and wait a second for the help 184In general, when in Doom, you can press `SPC` and wait a second for the help
185pane to appear with all available hotkey options. For example, you can press 185pane to appear with all available hotkey options. For example, you can press
@@ -205,7 +205,7 @@ expands further, allowing you to insert various markdown elements and toggle
205things like link hiding. 205things like link hiding.
206 206
207| Doom Hotkey | Function | 207| Doom Hotkey | Function |
208|------------------------------|--------------------------| 208| ---------------------------- | ------------------------ |
209| `SPC m '` | markdown-edit-code-block | 209| `SPC m '` | markdown-edit-code-block |
210| `SPC m e` | markdown-export | 210| `SPC m e` | markdown-export |
211| `SPC m i` | +insert | 211| `SPC m i` | +insert |
@@ -226,7 +226,7 @@ are 865 possible org-related functions you can run. I won't possibly be able to
226list them all, so I will simply cover a few of the basic commands I use myself. 226list them all, so I will simply cover a few of the basic commands I use myself.
227 227
228| Doom Hotkey | Function | 228| Doom Hotkey | Function |
229|----------------|---------------------------------------| 229| -------------- | ------------------------------------- |
230| `SPC m t` | org-todo | 230| `SPC m t` | org-todo |
231| `SPC n t` | org-todo-list | 231| `SPC n t` | org-todo-list |
232| `SPC o A` | org-agenda | 232| `SPC o A` | org-agenda |
@@ -262,8 +262,8 @@ list them all, so I will simply cover a few of the basic commands I use myself.
262 2. Add an empty `.projectile` file in the project root. 262 2. Add an empty `.projectile` file in the project root.
263 263
264 Once a project has been created, you can create custom publishing actions 264 Once a project has been created, you can create custom publishing actions
265 within your `~/.doom.d/config.el` file. For example, here's a test project 265 within your `~/.doom.d/config.el` file. For example, here's a test project I
266 I created to try and convert this blog to org-mode recently. 266 created to try and convert this blog to org-mode recently.
267 267
268 ```lisp 268 ```lisp
269 ;; org-publish 269 ;; org-publish
content/blog/2024-03-15-self-hosting-ddns-updater.md +28 −27
@@ -43,30 +43,31 @@ nano ~/ddns-updater/data/config.json
43 43
44When setting up the configuration for Cloudflare, you'll need the following: 44When setting up the configuration for Cloudflare, you'll need the following:
45 45
46- Required Parameters 46- Required Parameters
47 - `"zone_identifier"` is the Zone ID of your site from the domain overview 47 - `"zone_identifier"` is the Zone ID of your site from the domain overview
48 page 48 page
49 - `"host"` is your host and can be `"@"`, a subdomain or the wildcard `"*"`. 49 - `"host"` is your host and can be `"@"`, a subdomain or the wildcard
50 See [this issue comment for 50 `"*"`. See [this issue comment for
51 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949). 51 context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949).
52 - `"ttl"` integer value for record TTL in seconds (specify 1 for automatic) 52 - `"ttl"` integer value for record TTL in seconds (specify 1 for
53 - One of the following ([how to find API 53 automatic)
54 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)): 54 - One of the following ([how to find API
55 - Email `"email"` and Global API Key `"key"` 55 keys](https://developers.cloudflare.com/fundamentals/api/get-started/)):
56 - User service key `"user_service_key"` 56 - Email `"email"` and Global API Key `"key"`
57 - API Token `"token"`, configured with DNS edit permissions for your DNS 57 - User service key `"user_service_key"`
58 name's zone 58 - API Token `"token"`, configured with DNS edit permissions for your
59- Optional Parameters 59 DNS name's zone
60 - `"proxied"` can be set to `true` to use the proxy services of Cloudflare 60- Optional Parameters
61 - `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or 61 - `"proxied"` can be set to `true` to use the proxy services of Cloudflare
62 `ipv4 or ipv6` (update one of the two, depending on the public ip 62 - `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or
63 found). It defaults to `ipv4 or ipv6`. 63 `ipv4 or ipv6` (update one of the two, depending on the public ip
64 - `"ipv6_suffix"` is the IPv6 interface identifier suffix to use. It can be 64 found). It defaults to `ipv4 or ipv6`.
65 for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults 65 - `"ipv6_suffix"` is the IPv6 interface identifier suffix to use. It can
66 to no suffix and the raw public IPv6 address obtained is used in the 66 be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it
67 record updating. 67 defaults to no suffix and the raw public IPv6 address obtained is used
68 68 in the record updating.
69``` conf 69
70```conf
70{ 71{
71 "settings": [ 72 "settings": [
72 { 73 {
@@ -106,7 +107,7 @@ file.
106nano ~/ddns_-pdater/docker-compose.yml 107nano ~/ddns_-pdater/docker-compose.yml
107``` 108```
108 109
109``` config 110```config
110version: "3.7" 111version: "3.7"
111services: 112services:
112 ddns-updater: 113 ddns-updater:
@@ -169,7 +170,7 @@ sudo nano /etc/nginx/sites-available/ddns
169 170
170Here's a basic example that should work properly. 171Here's a basic example that should work properly.
171 172
172``` conf 173```conf
173server { 174server {
174 # If using 443, remember to include your ssl_certificate 175 # If using 443, remember to include your ssl_certificate
175 # and ssl_certificate_key 176 # and ssl_certificate_key
@@ -190,7 +191,7 @@ server {
190Here's a full example that uses my Authelia authentication service to require 191Here's a full example that uses my Authelia authentication service to require
191authentication before someone can access the web page. 192authentication before someone can access the web page.
192 193
193``` conf 194```conf
194server { 195server {
195 if ($host ~ ^[^.]+\.example\.com$) { 196 if ($host ~ ^[^.]+\.example\.com$) {
196 return 301 https://$host$request_uri; 197 return 301 https://$host$request_uri;
content/blog/2024-03-29-org-blog.md +3 −3
@@ -62,8 +62,8 @@ Either re-open Emacs or hit `SPC h r r` to reload the changes.
62 62
63## Configuration 63## Configuration
64 64
65Now that I've installed weblorg, I need to configure the project. I'll start 65Now that I've installed weblorg, I need to configure the project. I'll start by
66by navigating to my site's source code and creating a `publish.el` file. 66navigating to my site's source code and creating a `publish.el` file.
67 67
68```sh 68```sh
69cd ~/Source/cleberg.net && nano publish.el 69cd ~/Source/cleberg.net && nano publish.el
@@ -187,7 +187,7 @@ restriction is that the `publish.el` file must point to the correct paths.
187For my blog, I prefer to keep the blog content out of the top-level directory. 187For my blog, I prefer to keep the blog content out of the top-level directory.
188This results in the following structure (shortened for brevity): 188This results in the following structure (shortened for brevity):
189 189
190``` txt 190```txt
191.build/ 191.build/
192content/ 192content/
193 blog/ 193 blog/
content/blog/2024-04-08-docker-local-web-server.md +1 −1
@@ -84,7 +84,7 @@ docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/shar
84 84
85Here's an example of my development configuration file. 85Here's an example of my development configuration file.
86 86
87``` conf 87```conf
88# nginx-config.conf 88# nginx-config.conf
89server { 89server {
90 server_name cleberg.net www.cleberg.net; 90 server_name cleberg.net www.cleberg.net;
content/blog/2024-04-18-mu4e.md +2 −3
@@ -112,7 +112,7 @@ information and customize it to match your mail provider's information.
112nano ~/.maildir/.mbsyncrc 112nano ~/.maildir/.mbsyncrc
113``` 113```
114 114
115``` conf 115```conf
116IMAPAccount example 116IMAPAccount example
117Host imap.example.com 117Host imap.example.com
118User dummy@example.com 118User dummy@example.com
@@ -299,8 +299,7 @@ The emails will now to be ready to use!
299You can now launch Doom and open Mu4e with `SPC o m`. You can also explore the 299You can now launch Doom and open Mu4e with `SPC o m`. You can also explore the
300Mu4e options with `SPC : mu4e`. 300Mu4e options with `SPC : mu4e`.
301 301
302The home page shows various options and metdata about the account you've 302The home page shows various options and metdata about the account you've opened.
303opened.
304 303
305![Mu4e Home Page](https://img.cleberg.net/blog/20240418-mu4e/mu4e.png) 304![Mu4e Home Page](https://img.cleberg.net/blog/20240418-mu4e/mu4e.png)
306 305
content/salary.md +26 −8
@@ -5,20 +5,33 @@ draft = false
5 5
6# Salary Transparency 6# Salary Transparency
7 7
8The data below details the base salary information for each job I've held. This information is posted publicly to ensure others in my position have a solid reference point when determining if their current or proposed salary is appropriate. 8The data below details the base salary information for each job I've held. This
9information is posted publicly to ensure others in my position have a solid
10reference point when determining if their current or proposed salary is
11appropriate.
9 12
10While sites like Glassdoor are locking salary data behind a paywall, LinkedIn is discontinuing LinkedIn Salary, and helpful websites like Big 4 Transparency are extremely rare, I wanted to provide my personal data publicly and freely to those who need it. 13While sites like Glassdoor are locking salary data behind a paywall, LinkedIn is
14discontinuing LinkedIn Salary, and helpful websites like Big 4 Transparency are
15extremely rare, I wanted to provide my personal data publicly and freely to
16those who need it.
11 17
12I have seen what can happen when great employees don't know the market values for their skills and I happily help those in my teams, so I'm happy to extend this information to the online community. 18I have seen what can happen when great employees don't know the market values
19for their skills and I happily help those in my teams, so I'm happy to extend
20this information to the online community.
13 21
14As a final note, there are numerous reasons that people in the same role are paid differently (expertise, years of experience, certifications, education, etc.) and that the data in this table should only be used as a single point of reference, not the whole story. 22As a final note, there are numerous reasons that people in the same role are
23paid differently (expertise, years of experience, certifications, education,
24etc.) and that the data in this table should only be used as a single point of
25reference, not the whole story.
15 26
16# Salary Data 27# Salary Data
17 28
18Note: When in a role that gives periodic raises, I will create a new record with the new base salary in the table below. See the KPMG records for an example of a raise while in the same role. 29Note: When in a role that gives periodic raises, I will create a new record with
30the new base salary in the table below. See the KPMG records for an example of a
31raise while in the same role.
19 32
20| Title | Company | Location | Start | End | Salary | 33| Title | Company | Location | Start | End | Salary |
21|------------------------------------------------|------------------------|----------------|---------|---------|----------| 34| ---------------------------------------------- | ---------------------- | -------------- | ------- | ------- | -------- |
22| Senior Associate, Technology Assurance - Audit | KPMG | Omaha, NE | 2023-10 | Current | $116,700 | 35| Senior Associate, Technology Assurance - Audit | KPMG | Omaha, NE | 2023-10 | Current | $116,700 |
23| Senior Associate, Technology Assurance - Audit | KPMG | Omaha, NE | 2022-06 | 2023-10 | $110,000 | 36| Senior Associate, Technology Assurance - Audit | KPMG | Omaha, NE | 2022-06 | 2023-10 | $110,000 |
24| Senior Technology Risk Consultant | Ernst & Young | Des Moines, IA | 2021-09 | 2022-06 | $89,500 | 37| Senior Technology Risk Consultant | Ernst & Young | Des Moines, IA | 2021-09 | 2022-06 | $89,500 |
@@ -30,6 +43,11 @@ Note: When in a role that gives periodic raises, I will create a new record with
30| Teaching Assistant | University of Nebraska | Lincoln, NE | 2017-08 | 2018-05 | $7/hour | 43| Teaching Assistant | University of Nebraska | Lincoln, NE | 2017-08 | 2018-05 | $7/hour |
31| Community Management Intern | Walgreens | Lincoln, NE | 2017-06 | 2018-02 | $14/hour | 44| Community Management Intern | Walgreens | Lincoln, NE | 2017-06 | 2018-02 | $14/hour |
32 45
33This page was inspired by [Xe](https://xeiaso.net/salary-transparency/), and I'm quoting the following wording from them as I want to reiterate this piece: 46This page was inspired by [Xe](https://xeiaso.net/salary-transparency/), and I'm
47quoting the following wording from them as I want to reiterate this piece:
34 48
35> Please consider publishing your salary data like this as well. By open, voluntary transparency we can help to end stigmas around discussing pay and help ensure that the next generations of people in tech are treated fairly. Stigmas thrive in darkness but die in the light of day. You can help end the stigma by playing your cards out in the open like this. 49> Please consider publishing your salary data like this as well. By open,
50> voluntary transparency we can help to end stigmas around discussing pay and
51> help ensure that the next generations of people in tech are treated fairly.
52> Stigmas thrive in darkness but die in the light of day. You can help end the
53> stigma by playing your cards out in the open like this.
content/services.md +16 −11
@@ -3,15 +3,20 @@ title = "Services"
3draft = false 3draft = false
4+++ 4+++
5 5
6- [AnonymousOverflow](https://ao.cleberg.net/) - A StackOverflow proxy 6- [AnonymousOverflow](https://ao.cleberg.net/) - A StackOverflow proxy
7- [CyberChef](https://cyberchef.cleberg.net/) - The Cyber Swiss Army Knife 7- [CyberChef](https://cyberchef.cleberg.net/) - The Cyber Swiss Army Knife
8- [FileArchive](https://files.cleberg.net/) - An interesting file archive 8- [FileArchive](https://files.cleberg.net/) - An interesting file archive
9- [FlashPaper](https://paste.cleberg.net/) - One-time encrypted password/secret sharing 9- [FlashPaper](https://paste.cleberg.net/) - One-time encrypted
10- [GotHub](https://gh.cleberg.net/) - An alternative front-end for GitHub 10 password/secret sharing
11- [ifconfig.php](https://ip.cleberg.net/) - A "whatsmyip" tool 11- [GotHub](https://gh.cleberg.net/) - An alternative front-end for GitHub
12- [Invidious](https://invidious.cleberg.net/) - A YouTube proxy 12- [ifconfig.php](https://ip.cleberg.net/) - A "whatsmyip" tool
13- [Office](https://office.cleberg.net/) - The world's smallest office suite 13- [Invidious](https://invidious.cleberg.net/) - A YouTube proxy
14- [Org-Live](https://org.cleberg.net/) - A basic org-mode editor for the web I built 14- [Office](https://office.cleberg.net/) - The world's smallest office suite
15- [SearXNG](https://search.cleberg.net/) - A privacy-respecting, open metasearch engine 15- [Org-Live](https://org.cleberg.net/) - A basic org-mode editor for the web I
16 built
17- [SearXNG](https://search.cleberg.net/) - A privacy-respecting, open
18 metasearch engine
16 19
17See the [git log](https://git.cleberg.net/?p=cleberg.net.git;a=history;f=content/services/index.org;h=b9ecca2567a02711a33bb633d45f790610ed9214;hb=HEAD) if you want to see changes that have been made. 20See the [git
21log](https://git.cleberg.net/?p=cleberg.net.git;a=history;f=content/services/index.org;h=b9ecca2567a02711a33bb633d45f790610ed9214;hb=HEAD)
22if you want to see changes that have been made.
content/wiki/blogroll.md +20 −16
@@ -6,30 +6,34 @@ draft = false
6 6
7## Aggregators 7## Aggregators
8 8
9 - [1MB Club](https://1mb.club/) 9- [1MB Club](https://1mb.club/)
10 - [250KB Club](https://250kb.club/) 10- [250KB Club](https://250kb.club/)
11 - [512KB Club](https://512kb.club/) 11- [512KB Club](https://512kb.club/)
12 - [Darktheme Club](https://darktheme.club/) 12- [Darktheme Club](https://darktheme.club/)
13 - [No CSS Club](https://nocss.club/) 13- [No CSS Club](https://nocss.club/)
14 - [No-JS Club](https://no-js.club/) 14- [No-JS Club](https://no-js.club/)
15 - [Ye Olde Blogroll](https://blogroll.org/) 15- [Ye Olde Blogroll](https://blogroll.org/)
16 16
17## Plain Text 17## Plain Text
18 18
19A list of various plaintext websites and lists. 19A list of various plaintext websites and lists.
20 20
21 - [A List Of Text-Only & Minimalist News Sites](https://greycoder.com/a-list-of-text-only-new-sites/) 21- [A List Of Text-Only & Minimalist News
22 - [Harvard Law Review](https://harvardlawreview.org/) 22 Sites](https://greycoder.com/a-list-of-text-only-new-sites/)
23 - [Hyperlinked Text](https://sjmulder.nl/en/textonly.html) 23- [Harvard Law Review](https://harvardlawreview.org/)
24 - [Plain-text web design](https://medium.com/@letsworkshop/plain-text-web-design-a78ccaf9dbc0) 24- [Hyperlinked Text](https://sjmulder.nl/en/textonly.html)
25 - [Plaintext World](https://plaintextworld.com/) 25- [Plain-text web
26 - [Words](https://justinjackson.ca/words.html) 26 design](https://medium.com/@letsworkshop/plain-text-web-design-a78ccaf9dbc0)
27- [Plaintext World](https://plaintextworld.com/)
28- [Words](https://justinjackson.ca/words.html)
27 29
28## Webrings 30## Webrings
29 31
30Instead of listing my personal favorites, I'm just going to drop a link to [brisay's webring list](https://brisray.com/web/webring-list.htm), which contains 237 webrings for a total of 7078 websites, as of 2024-03-15. 32Instead of listing my personal favorites, I'm just going to drop a link to
33[brisay's webring list](https://brisray.com/web/webring-list.htm), which
34contains 237 webrings for a total of 7078 websites, as of 2024-03-15.
31 35
32## Everything Else 36## Everything Else
33 37
34 - [Dead Simple Sites](https://deadsimplesites.com/) 38- [Dead Simple Sites](https://deadsimplesites.com/)
35 - [Planet Emacslife](https://planet.emacslife.com/) 39- [Planet Emacslife](https://planet.emacslife.com/)
content/wiki/hardware.md +63 −41
@@ -11,7 +11,7 @@ draft = false
11Probably should have added more RAM but Macbooks are stupid expensive. 11Probably should have added more RAM but Macbooks are stupid expensive.
12 12
13| Category | Details | 13| Category | Details |
14|----------|-------------------------------------------------------| 14| -------- | ----------------------------------------------------- |
15| Model | [Macbook Pro 16"](https://www.apple.com/macbook-pro/) | 15| Model | [Macbook Pro 16"](https://www.apple.com/macbook-pro/) |
16| CPU | Apple M2 Pro | 16| CPU | Apple M2 Pro |
17| RAM | 16GB | 17| RAM | 16GB |
@@ -21,19 +21,19 @@ Probably should have added more RAM but Macbooks are stupid expensive.
21 21
22A beauty. 22A beauty.
23 23
24| Category | Details | 24| Category | Details |
25|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------| 25| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
26| Model | [Lenovo ThinkPad E15 Gen 4, model 21ED0048US](https://www.lenovo.com/us/en/p/laptops/thinkpad/thinkpade/thinkpad--e15-gen-4-(15-inch-amd)/len101t0023) | 26| Model | [Lenovo ThinkPad E15 Gen 4, model 21ED0048US](<https://www.lenovo.com/us/en/p/laptops/thinkpad/thinkpade/thinkpad--e15-gen-4-(15-inch-amd)/len101t0023>) |
27| CPU | AMD Ryzen 5 5625U with Radeon Graphics | 27| CPU | AMD Ryzen 5 5625U with Radeon Graphics |
28| RAM | 16 GB | 28| RAM | 16 GB |
29| Storage | 256 GB SSD | 29| Storage | 256 GB SSD |
30 30
31## Mobile 31## Mobile
32 32
33Previously used a Pixel 6 & Pixel 7 with GrapheneOS. 33Previously used a Pixel 6 & Pixel 7 with GrapheneOS.
34 34
35| Category | Details | 35| Category | Details |
36|----------|-----------------------------------------------------------| 36| -------- | --------------------------------------------------------- |
37| Model | [iPhone 15 Pro Max](https://www.apple.com/iphone-15-pro/) | 37| Model | [iPhone 15 Pro Max](https://www.apple.com/iphone-15-pro/) |
38| CPU | A17 Pro | 38| CPU | A17 Pro |
39| RAM | 8GB | 39| RAM | 8GB |
@@ -41,55 +41,77 @@ Previously used a Pixel 6 & Pixel 7 with GrapheneOS.
41 41
42## Homelab 42## Homelab
43 43
44I run a small homelab with a mix of consumer (compute/storage) and 44I run a small homelab with a mix of consumer (compute/storage) and enterprise
45enterprise (network) hardware. I try to keep the lab energy efficient 45(network) hardware. I try to keep the lab energy efficient and quiet as my top
46and quiet as my top priorities. 46priorities.
47 47
48### IoT 48### IoT
49 49
50A collection of mainly smart lights, sensors, and smart appliances. My first preference is to disable all networking for new smart devices or simply not connect internet in the first place (e.g. I never enable internet on my smart TVs). If the smart device requires LAN access, I will connect the device to my guest-restricted IoT network. As a last resort, I will set-up the internet but monitor the DNS lookups via NextDNS and forcibly block any domains I do not want the device to be using. If the device is egregious or shady, I'll just sell it and either replace it or live without it. 50A collection of mainly smart lights, sensors, and smart appliances. My first
51preference is to disable all networking for new smart devices or simply not
52connect internet in the first place (e.g. I never enable internet on my smart
53TVs). If the smart device requires LAN access, I will connect the device to my
54guest-restricted IoT network. As a last resort, I will set-up the internet but
55monitor the DNS lookups via NextDNS and forcibly block any domains I do not want
56the device to be using. If the device is egregious or shady, I'll just sell it
57and either replace it or live without it.
51 58
52- Other Appliances (washer, dryer, humidifier, fans, etc.) 59- Other Appliances (washer, dryer, humidifier, fans, etc.)
53 - [Roomba i7+](https://about.irobot.com/sitecore/content/north-america/irobot-us/home/roomba/i7-series) 60- [Roomba
54 - [Philips Hue A19 Bulbs](https://www.philips-hue.com/en-us/p/hue-white-and-color-ambiance-a19---e26-smart-bulb---60-w--3-pack-/046677562786) x 15 61 i7+](https://about.irobot.com/sitecore/content/north-america/irobot-us/home/roomba/i7-series)
55 - [Philips Hue Play Light Bars](https://www.philips-hue.com/en-us/p/hue-bundle-play-blk-ext/33001) 62- [Philips Hue A19
56 - [Philips Hue Smart Bridge](https://www.philips-hue.com/en-us/p/hue-bridge/046677458478) + play light bars and a ton of bulbs 63 Bulbs](https://www.philips-hue.com/en-us/p/hue-white-and-color-ambiance-a19---e26-smart-bulb---60-w--3-pack-/046677562786)
57 - [UP Chime](https://store.ui.com/us/en/collections/unifi-camera-security-special-chime) 64 x 15
58 - [UP-Sense](https://store.ui.com/us/en/collections/unifi-camera-security-special-sensor) x 2 65- [Philips Hue Play Light
59 - [USP-Plug](https://store.ui.com/us/en/products/unifi-smart-power) 66 Bars](https://www.philips-hue.com/en-us/p/hue-bundle-play-blk-ext/33001)
60 - [UVC G4 Instant](https://store.ui.com/us/en/collections/unifi-camera-security-compact-wifi-connected) x 3 67- [Philips Hue Smart
61 - [UVC G4 Doorbell Pro](https://store.ui.com/us/en/collections/unifi-camera-security-special-wifi-doorbell) 68 Bridge](https://www.philips-hue.com/en-us/p/hue-bridge/046677458478) + play
69 light bars and a ton of bulbs
70- [UP
71 Chime](https://store.ui.com/us/en/collections/unifi-camera-security-special-chime)
72- [UP-Sense](https://store.ui.com/us/en/collections/unifi-camera-security-special-sensor)
73 x 2
74- [USP-Plug](https://store.ui.com/us/en/products/unifi-smart-power)
75- [UVC G4
76 Instant](https://store.ui.com/us/en/collections/unifi-camera-security-compact-wifi-connected)
77 x 3
78- [UVC G4 Doorbell
79 Pro](https://store.ui.com/us/en/collections/unifi-camera-security-special-wifi-doorbell)
62 80
63### Network 81### Network
64 82
65A rack-mounted Dream Machine Pro, connected downstream to an access point, mesh extender, and a couple ethernet switches. 83A rack-mounted Dream Machine Pro, connected downstream to an access point, mesh
84extender, and a couple ethernet switches.
66 85
67 - [UDM-Pro](https://store.ui.com/us/en/collections/unifi-dream-machine/products/udm-pro) 86- [UDM-Pro](https://store.ui.com/us/en/collections/unifi-dream-machine/products/udm-pro)
68 - [USW-24-PoE](https://store.ui.com/us/en/collections/unifi-switching-standard-power-over-ethernet/products/usw-24-poe) 87- [USW-24-PoE](https://store.ui.com/us/en/collections/unifi-switching-standard-power-over-ethernet/products/usw-24-poe)
69 - [USW-Lite-8-PoE](https://store.ui.com/us/en/collections/unifi-switching-utility-poe/products/usw-lite-8-poe) 88- [USW-Lite-8-PoE](https://store.ui.com/us/en/collections/unifi-switching-utility-poe/products/usw-lite-8-poe)
70 - [U6-Pro](https://store.ui.com/us/en/collections/unifi-wifi-flagship-high-capacity/products/u6-pro) 89- [U6-Pro](https://store.ui.com/us/en/collections/unifi-wifi-flagship-high-capacity/products/u6-pro)
71 - [U6-Extender](https://store.ui.com/us/en/collections/unifi-wifi-inwall-outlet-mesh) 90- [U6-Extender](https://store.ui.com/us/en/collections/unifi-wifi-inwall-outlet-mesh)
72 - [USW 24-Port Patch Panel](https://store.ui.com/us/en/collections/unifi-accessory-tech-installations-rackmount/products/uacc-rack-panel-patch-blank-24) 91- [USW 24-Port Patch
92 Panel](https://store.ui.com/us/en/collections/unifi-accessory-tech-installations-rackmount/products/uacc-rack-panel-patch-blank-24)
73 93
74### Servers 94### Servers
75 95
761. Rack-Mount Server 961. Rack-Mount Server
77 97
78 I wasn't happy with using low-powered PCs as servers and I knew I did not want the ear-shattering enterprise rack-mounted servers, so I built my own. 98 I wasn't happy with using low-powered PCs as servers and I knew I did not
99 want the ear-shattering enterprise rack-mounted servers, so I built my own.
79 100
80 | Category | Details | 101 | Category | Details |
81 |--------------------|----------------------------------------| 102 | ------------------ | -------------------------------------- |
82 | Case | Rosewill RSV-R4100U 4U | 103 | Case | Rosewill RSV-R4100U 4U |
83 | Motherboard | NZXT B550 | 104 | Motherboard | NZXT B550 |
84 | CPU | AMD Ryzen 7 5700G with Radeon Graphics | 105 | CPU | AMD Ryzen 7 5700G with Radeon Graphics |
85 | RAM | 64GB RAM (2x32GB) | 106 | RAM | 64GB RAM (2x32GB) |
86 | Storage (On-board) | Western Digital 500GB M.2 NVME SSD | 107 | Storage (On-board) | Western Digital 500GB M.2 NVME SSD |
87 | Storage (HDD Bay) | 48TB HDD | 108 | Storage (HDD Bay) | 48TB HDD |
88 | PSU | Corsair RM850 PSU | 109 | PSU | Corsair RM850 PSU |
89 110
902. Other 1112. Other
91 112
92 These ran as my main servers before I built the rack-mounted server above. I have shut these down indefinitely for now as I have no use for them. 113 These ran as my main servers before I built the rack-mounted server above. I
114 have shut these down indefinitely for now as I have no use for them.
93 115
94 - Dell OptiPlex 116 - Dell OptiPlex
95 - Raspberry Pi 4 117 - Raspberry Pi 4
content/wiki/ios.md +135 −87
@@ -6,9 +6,10 @@ draft = false
6 6
7Related: 7Related:
8 8
9- [Hardware](/wiki/hardware.html) 9- [Hardware](/wiki/hardware.html)
10 10
11My primary mobile OS. Currently running iOS 17. This wiki page contains most of the apps I have used at one point or another across my different iPhones. 11My primary mobile OS. Currently running iOS 17. This wiki page contains most of
12the apps I have used at one point or another across my different iPhones.
12 13
13(`*`) = My favorites 14(`*`) = My favorites
14 15
@@ -16,141 +17,188 @@ My primary mobile OS. Currently running iOS 17. This wiki page contains most of
16 17
17### Display 18### Display
18 19
19- Light Mode 20- Light Mode
20 - 10:00 to 16:00 21 - 10:00 to 16:00
21- Dark Mode 22- Dark Mode
22 - 16:00 to 10:00 23 - 16:00 to 10:00
23 24
24### Focus Modes 25### Focus Modes
25 26
26- Personal Focus 27- Personal Focus
27 - 06:00 to 21:00 28 - 06:00 to 21:00
28 - Allow Notifications From: 29 - Allow Notifications From:
29 - Alarms 30 - Alarms
30 - Calendar 31 - Calendar
31 - Contacts (1 person) 32 - Contacts (1 person)
32 - Messages 33 - Messages
33 - Phone 34 - Phone
34 - Reminders 35 - Reminders
35 - Signal 36 - Signal
36 - UniFi Protect 37 - UniFi Protect
37- Sleep Focus 38- Sleep Focus
38 - 21:00 to 06:00 39 - 21:00 to 06:00
39 - Allow Notifications From: 40 - Allow Notifications From:
40 - Alarms 41 - Alarms
41 - Contacts (1 person) 42 - Contacts (1 person)
42 - Reminders 43 - Reminders
43 - Signal 44 - Signal
44 45
45### Privacy & Security 46### Privacy & Security
46 47
47I generally follow the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) by only permitting the bare minimum privileges and revoking as soon as they are no longer required. 48I generally follow the [principle of least
49privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) by only
50permitting the bare minimum privileges and revoking as soon as they are no
51longer required.
48 52
49Here's the baseline I start with: 53Here's the baseline I start with:
50 54
51- Disable: 55- Disable:
52 - Analytics & Improvements 56 - Analytics & Improvements
53 - Apple Advertising 57 - Apple Advertising
54 - Apple ID > Sign-In & Security > Two-Factor Authentication 58 - Apple ID > Sign-In & Security > Two-Factor Authentication
55 - Location Services > System Services > Product Improvement 59 - Location Services > System Services > Product Improvement
56 - Tracking > Allow Apps to Request to Track 60 - Tracking > Allow Apps to Request to Track
57 - Safari > Advanced > Privacy Preserving Ad Measurement 61 - Safari > Advanced > Privacy Preserving Ad Measurement
58- Enable: 62- Enable:
59 - Apple ID > iCloud > Advanced Data Protection 63 - Apple ID > iCloud > Advanced Data Protection
60 - Apple ID > Personal Information > Communication Preferences 64 - Apple ID > Personal Information > Communication Preferences
61 - App Privacy Report 65 - App Privacy Report
62 - Location Services only for Camera, Find My, UDisc, & WiFiman 66 - Location Services only for Camera, Find My, UDisc, & WiFiman (`While
63 (`While Using`) 67 Using`)
64 - Safari > Prevent Cross-Site Tracking 68 - Safari > Prevent Cross-Site Tracking
65 - Safari > Hide IP Address 69 - Safari > Hide IP Address
66 - Safari > Advanced > Advanced Tracking and Fingerprinting 70 - Safari > Advanced > Advanced Tracking and Fingerprinting Protection
67 Protection
68 71
69## Native Apps 72## Native Apps
70 73
71### Business 74### Business
72 75
73- [Element](https://apps.apple.com/us/app/element-messenger/id1083446067) - A cross-platform messenger, based on Matrix 76- [Element](https://apps.apple.com/us/app/element-messenger/id1083446067) - A
74- [LinkedIn](https://apps.apple.com/us/app/linkedin-network-job-finder/id288429040) - One of the only social media apps I use 77 cross-platform messenger, based on Matrix
78- [LinkedIn](https://apps.apple.com/us/app/linkedin-network-job-finder/id288429040)
79 - One of the only social media apps I use
75 80
76### Developer Tools 81### Developer Tools
77 82
78- [Harbour](https://testflight.apple.com/join/F2vK7xo4) - Easily manage your Portainer service 83- [Harbour](https://testflight.apple.com/join/F2vK7xo4) - Easily manage your
79- [iSH](https://apps.apple.com/us/app/ish-shell/id1436902243) - A local shell with SSH functionality 84 Portainer service
85- [iSH](https://apps.apple.com/us/app/ish-shell/id1436902243) - A local shell
86 with SSH functionality
80 87
81### Entertainment 88### Entertainment
82 89
83- [Plex](https://apps.apple.com/us/app/plex-watch-live-tv-and-movies/id383457673) - A client for the Plex Media Server 90- [Plex](https://apps.apple.com/us/app/plex-watch-live-tv-and-movies/id383457673)
84- [Steam](https://apps.apple.com/us/app/steam-mobile/id495369748) - The top gaming marketplace for computers 91 - A client for the Plex Media Server
92- [Steam](https://apps.apple.com/us/app/steam-mobile/id495369748) - The top
93 gaming marketplace for computers
85 94
86### Lifestyle 95### Lifestyle
87 96
88- [Home](https://apps.apple.com/us/app/home/id1110145103) (`*`) - Apple homekit powered smart home manager 97- [Home](https://apps.apple.com/us/app/home/id1110145103) (`*`) - Apple
89- [Hue](https://apps.apple.com/us/app/philips-hue/id1055281310) - Philips Hue smart home manager 98 homekit powered smart home manager
90- [iRobot](https://apps.apple.com/us/app/irobot-home/id1012014442) - Manage iRobot Roomba devices 99- [Hue](https://apps.apple.com/us/app/philips-hue/id1055281310) - Philips Hue
91- [UniFi Protect](https://apps.apple.com/us/app/unifi-protect/id1392492235) - View and manage most UniFi Protect cameras and settings 100 smart home manager
101- [iRobot](https://apps.apple.com/us/app/irobot-home/id1012014442) - Manage
102 iRobot Roomba devices
103- [UniFi Protect](https://apps.apple.com/us/app/unifi-protect/id1392492235) -
104 View and manage most UniFi Protect cameras and settings
92 105
93### Music 106### Music
94 107
95- [Apple Music](https://apps.apple.com/us/app/apple-music/id1108187390) (`*`) - Apple's native music streaming app 108- [Apple Music](https://apps.apple.com/us/app/apple-music/id1108187390) (`*`)
96- [Plexamp](https://apps.apple.com/us/app/plexamp/id1500797510) (`*`) - Top-notch music app for your Plex Media Server, with a neural network that provides excellent radio/shuffle suggestions 109 - Apple's native music streaming app
110- [Plexamp](https://apps.apple.com/us/app/plexamp/id1500797510) (`*`) -
111 Top-notch music app for your Plex Media Server, with a neural network that
112 provides excellent radio/shuffle suggestions
97 113
98### Navigation 114### Navigation
99 115
100- [deedum](https://apps.apple.com/us/app/deedum/id1546810946) - A Gemini Protocol browser 116- [deedum](https://apps.apple.com/us/app/deedum/id1546810946) - A Gemini
117 Protocol browser
101 118
102### News 119### News
103 120
104- [NetNewsWire](https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210) - A free and open source RSS reader for Mac, iPhone, and iPad 121- [NetNewsWire](https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210)
122 - A free and open source RSS reader for Mac, iPhone, and iPad
105 123
106### Photo & Video 124### Photo & Video
107 125
108- [Aislingeach](https://testflight.apple.com/join/Q6WyyEpS) - A quick way to generate and rate images from the Stable Horde 126- [Aislingeach](https://testflight.apple.com/join/Q6WyyEpS) - A quick way to
109- [Unsplash](https://apps.apple.com/us/app/unsplash/id1290631746) - Premium images, mostly free 127 generate and rate images from the Stable Horde
128- [Unsplash](https://apps.apple.com/us/app/unsplash/id1290631746) - Premium
129 images, mostly free
110 130
111### Productivity 131### Productivity
112 132
113- [beorg](https://apps.apple.com/us/app/beorg-to-do-list-agenda/id1238649962) - An org-mode editor, outline, and scheduler with paid extensions 133- [beorg](https://apps.apple.com/us/app/beorg-to-do-list-agenda/id1238649962)
114- [Bitwarden](https://apps.apple.com/us/app/bitwarden-password-manager/id1137397744) (`*`) - An open source password manager 134 - An org-mode editor, outline, and scheduler with paid extensions
115- [Bitwarden Authenticator](https://apps.apple.com/us/app/bitwarden-authenticator/id6497335175) (`*`) - Generate 2FA on your device 135- [Bitwarden](https://apps.apple.com/us/app/bitwarden-password-manager/id1137397744)
116- [Cryptomator](https://apps.apple.com/us/app/cryptomator/id1560822163) - A cross-platform encryption program 136 (`*`) - An open source password manager
117- [Obsidian](https://apps.apple.com/us/app/obsidian-connected-notes/id1557175442) (`*`) - A nice Markdown-based editor based on a "vault" structure. Offers a paid sync solution and community extensions 137- [Bitwarden
118- [Strongbox](https://apps.apple.com/us/app/strongbox-password-manager/id897283731) - Keepass password manager for iOS & macOS 138 Authenticator](https://apps.apple.com/us/app/bitwarden-authenticator/id6497335175)
119- [UniFi Network](https://apps.apple.com/us/app/unifi/id1057750338) - View and manage most UniFi Network settings 139 (`*`) - Generate 2FA on your device
140- [Cryptomator](https://apps.apple.com/us/app/cryptomator/id1560822163) - A
141 cross-platform encryption program
142- [Obsidian](https://apps.apple.com/us/app/obsidian-connected-notes/id1557175442)
143 (`*`) - A nice Markdown-based editor based on a "vault" structure. Offers a
144 paid sync solution and community extensions
145- [Strongbox](https://apps.apple.com/us/app/strongbox-password-manager/id897283731)
146 - Keepass password manager for iOS & macOS
147- [UniFi Network](https://apps.apple.com/us/app/unifi/id1057750338) - View and
148 manage most UniFi Network settings
120 149
121### Safari Extensions 150### Safari Extensions
122 151
123- [AdGuard](https://apps.apple.com/us/app/adguard-adblock-privacy/id1047223162) - 152- [AdGuard](https://apps.apple.com/us/app/adguard-adblock-privacy/id1047223162)
124 Ad blocker 153 - Ad blocker
125- [Dark Reader](https://apps.apple.com/us/app/dark-reader-for-safari/id1438243180) - Dark mode for all the sites 154- [Dark
126- [PiPifier](https://apps.apple.com/us/app/pipifier/id1234771095) - Force videos to support PiP 155 Reader](https://apps.apple.com/us/app/dark-reader-for-safari/id1438243180) -
127- [Privacy Redirect](https://apps.apple.com/us/app/privacy-redirect/id1578144015) - Redirect select websites to others, usually to privacy-focused alternatives 156 Dark mode for all the sites
157- [PiPifier](https://apps.apple.com/us/app/pipifier/id1234771095) - Force
158 videos to support PiP
159- [Privacy
160 Redirect](https://apps.apple.com/us/app/privacy-redirect/id1578144015) -
161 Redirect select websites to others, usually to privacy-focused alternatives
128 162
129### Social Networking 163### Social Networking
130 164
131- [MultiTab T](https://apps.apple.com/us/app/multitab-for-tumblr/id1071533778) (`*`) - A gallery-based Tumblr client with some unique features, such as tab history and sync 165- [MultiTab T](https://apps.apple.com/us/app/multitab-for-tumblr/id1071533778)
132- [Signal](https://apps.apple.com/us/app/signal-private-messenger/id874139669) (`*`) - A simple, powerful, and secure messenger 166 (`*`) - A gallery-based Tumblr client with some unique features, such as tab
133- [Three Cheers](https://testflight.apple.com/join/mpVk1qIy) - A client for Tildes.net with a design focus that matches the intent of Tildes 167 history and sync
134- [Voyager](https://apps.apple.com/us/app/voyager-for-lemmy/id6451429762) - A Lemmy client 168- [Signal](https://apps.apple.com/us/app/signal-private-messenger/id874139669)
169 (`*`) - A simple, powerful, and secure messenger
170- [Three Cheers](https://testflight.apple.com/join/mpVk1qIy) - A client for
171 Tildes.net with a design focus that matches the intent of Tildes
172- [Voyager](https://apps.apple.com/us/app/voyager-for-lemmy/id6451429762) - A
173 Lemmy client
135 174
136### Sports 175### Sports
137 176
138- [Apple Sports](https://apps.apple.com/us/app/apple-sports/id6446788829) - Apple's new sports app - lacks notifications and live events 177- [Apple Sports](https://apps.apple.com/us/app/apple-sports/id6446788829) -
139- [UDisc](https://apps.apple.com/us/app/udisc-disc-golf/id1072228953) - Disc golf course maps, score cards, and more 178 Apple's new sports app - lacks notifications and live events
179- [UDisc](https://apps.apple.com/us/app/udisc-disc-golf/id1072228953) - Disc
180 golf course maps, score cards, and more
140 181
141### Utilities 182### Utilities
142 183
143- [Backblaze](https://apps.apple.com/us/app/backblaze/id628638330) - Quickly view and manage Backblaze b2 cloud storage 184- [Backblaze](https://apps.apple.com/us/app/backblaze/id628638330) - Quickly
144- [Mullvad VPN](https://apps.apple.com/us/app/mullvad-vpn/id1488466513) (`*`) - A private VPN service 185 view and manage Backblaze b2 cloud storage
145- [OTP Auth](https://apps.apple.com/us/app/otp-auth/id659877384) (`*`) - A minimalistic OTP app with support for biometrics, custom icons, import/export, and iCloud sync 186- [Mullvad VPN](https://apps.apple.com/us/app/mullvad-vpn/id1488466513) (`*`)
146- [Plex Dash](https://apps.apple.com/us/app/plex-dash/id1500797677) - Stats about your Plex Media Server 187 - A private VPN service
147- [Safari](https://apps.apple.com/us/app/safari/id1146562112) - iOS default browser 188- [OTP Auth](https://apps.apple.com/us/app/otp-auth/id659877384) (`*`) - A
148- [Unifi WiFiman](https://apps.apple.com/us/app/ubiquiti-wifiman/id1385561119) - Create visual layouts of WiFi strength and save heat maps to your phone 189 minimalistic OTP app with support for biometrics, custom icons,
190 import/export, and iCloud sync
191- [Plex Dash](https://apps.apple.com/us/app/plex-dash/id1500797677) - Stats
192 about your Plex Media Server
193- [Safari](https://apps.apple.com/us/app/safari/id1146562112) - iOS default
194 browser
195- [Unifi WiFiman](https://apps.apple.com/us/app/ubiquiti-wifiman/id1385561119)
196 - Create visual layouts of WiFi strength and save heat maps to your phone
149 197
150## Web Apps & Shortcuts 198## Web Apps & Shortcuts
151 199
152- [Brutalist Report](https://brutalist.report/) - Minimal news aggregator 200- [Brutalist Report](https://brutalist.report/) - Minimal news aggregator
153- [_Cyber.Report](https://cyber.report/) - Cybersecurity news aggregator 201- [\_Cyber.Report](https://cyber.report/) - Cybersecurity news aggregator
154- [Hacker News](https://news.ycombinator.com/) - Mostly technical news 202- [Hacker News](https://news.ycombinator.com/) - Mostly technical news
155- [NextDNS](https://nextdns.io/) - NextDNS statistics dashboard 203- [NextDNS](https://nextdns.io/) - NextDNS statistics dashboard
156- [Readspike](https://readspike.com/) - Minimal news aggregator 204- [Readspike](https://readspike.com/) - Minimal news aggregator
content/wiki/macos.md +99 −54
@@ -6,9 +6,10 @@ draft = false
6 6
7Related: 7Related:
8 8
9- [Hardware](/wiki/hardware/) 9- [Hardware](/wiki/hardware/)
10 10
11My primary OS. Currently running macOS Sonoma 14. This wiki page contains most of the apps I have used at one point or another across my different Macbooks. 11My primary OS. Currently running macOS Sonoma 14. This wiki page contains most
12of the apps I have used at one point or another across my different Macbooks.
12 13
13(`*`) = My favorites 14(`*`) = My favorites
14 15
@@ -16,13 +17,14 @@ My primary OS. Currently running macOS Sonoma 14. This wiki page contains most o
16 17
17### Disable System Services 18### Disable System Services
18 19
19- [Disabling and Enabling System Integrity 20- [Disabling and Enabling System Integrity
20 Protection](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection) 21 Protection](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection)
21- Disable Gatekeeper: `sudo spctl --master-disable` 22- Disable Gatekeeper: `sudo spctl --master-disable`
22 23
23### Dotfiles 24### Dotfiles
24 25
25These are probably out of date, but they give a general idea of how I configure my machine. 26These are probably out of date, but they give a general idea of how I configure
27my machine.
26 28
27```conf 29```conf
28# ~/.zshrc 30# ~/.zshrc
@@ -81,70 +83,113 @@ echo "yabai configuration loaded.."
81 83
82### Browsers 84### Browsers
83 85
84- [Librewolf](https://librewolf.net/) (`*`) - Custom version of Firefox, focused on privacy and security 86- [Librewolf](https://librewolf.net/) (`*`) - Custom version of Firefox,
85 - [Bitwarden](https://bitwarden.com/) - An open source password manager 87 focused on privacy and security
86 - [Dark Reader](https://darkreader.org/) - Dark mode for all the websites 88 - [Bitwarden](https://bitwarden.com/) - An open source password manager
87 - [Libredirect](https://libredirect.github.io/) - Automatic web redirections 89 - [Dark Reader](https://darkreader.org/) - Dark mode for all the websites
88 - [Strongbox](https://strongboxsafe.com/) - Keepass password manager for iOS & macOS 90 - [Libredirect](https://libredirect.github.io/) - Automatic web
89 - [uBlock Origin](https://ublockorigin.com/) - Free, open-source ad content blocker 91 redirections
90- [Ungoogled Chromium](https://github.com/ungoogled-software/ungoogled-chromium) - Google Chromium, sans integration with Google 92 - [Strongbox](https://strongboxsafe.com/) - Keepass password manager for
91- [eww](https://www.gnu.org/software/emacs/manual/html_mono/eww.html) - Emacs Web Wowser, for TUI browsing 93 iOS & macOS
94 - [uBlock Origin](https://ublockorigin.com/) - Free, open-source ad
95 content blocker
96- [Ungoogled
97 Chromium](https://github.com/ungoogled-software/ungoogled-chromium) - Google
98 Chromium, sans integration with Google
99- [eww](https://www.gnu.org/software/emacs/manual/html_mono/eww.html) - Emacs
100 Web Wowser, for TUI browsing
92 101
93### Communications 102### Communications
94 103
95- [Element](https://element.io/) (`*`) - Matrix's default GUI client 104- [Element](https://element.io/) (`*`) - Matrix's default GUI client
96- [gomuks](https://github.com/tulir/gomuks) - A terminal based Matrix client 105- [gomuks](https://github.com/tulir/gomuks) - A terminal based Matrix client
97- [Thunderbird](https://www.thunderbird.net/) (`*`) - An open source email client by Mozilla 106- [Thunderbird](https://www.thunderbird.net/) (`*`) - An open source email
98- [Signal](https://signal.org/) (`*`) - A simple, powerful, and secure messenger 107 client by Mozilla
108- [Signal](https://signal.org/) (`*`) - A simple, powerful, and secure
109 messenger
99 110
100### Development 111### Development
101 112
102- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - Docker containers for your desktop 113- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - Docker
103 - [open-webui](https://github.com/open-webui/open-webui) - User-friendly WebUI for LLMs 114 containers for your desktop
104- [iTerm2](https://iterm2.com/) (`*`) - The best terminal for macOS, hands down 115 - [open-webui](https://github.com/open-webui/open-webui) - User-friendly
105- [Podman Desktop](https://podman-desktop.io/) (`*`) - Open source tool for containers and Kubernetes 116 WebUI for LLMs
106- [Xcode](https://developer.apple.com/xcode/) - Apple's IDE 117- [iTerm2](https://iterm2.com/) (`*`) - The best terminal for macOS, hands
107- [zsh](https://en.wikipedia.org/wiki/Z_shell) (`*`) - My shell preference due to its plugin and theme community 118 down
108 - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) - Fish-like autosuggestions for zsh 119- [Podman Desktop](https://podman-desktop.io/) (`*`) - Open source tool for
109 - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) - Fish shell like syntax highlighting for Zsh 120 containers and Kubernetes
121- [Xcode](https://developer.apple.com/xcode/) - Apple's IDE
122- [zsh](https://en.wikipedia.org/wiki/Z_shell) (`*`) - My shell preference due
123 to its plugin and theme community
124 - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)
125 - Fish-like autosuggestions for zsh
126 - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting)
127 - Fish shell like syntax highlighting for Zsh
110 128
111### Editors 129### Editors
112 130
113- [Doom Emacs](https://github.com/doomemacs/doomemacs) (`*`) - An Emacs framework, great for working in org-mode 131- [Doom Emacs](https://github.com/doomemacs/doomemacs) (`*`) - An Emacs
114- [Obsidian](https://obsidian.md/) - A nice Markdown-based editor based on a "vault" structure. Offers a paid sync solution and community extensions 132 framework, great for working in org-mode
115- [Standard Notes](https://standardnotes.com/) - A simple text editor focused on privacy and security. Offers a paid sync solution and community extensions 133- [Obsidian](https://obsidian.md/) - A nice Markdown-based editor based on a
116- [VSCodium](https://vscodium.com/) - VS Code without proprietary blobs 134 "vault" structure. Offers a paid sync solution and community extensions
135- [Standard Notes](https://standardnotes.com/) - A simple text editor focused
136 on privacy and security. Offers a paid sync solution and community
137 extensions
138- [VSCodium](https://vscodium.com/) - VS Code without proprietary blobs
117 139
118### Media 140### Media
119 141
120- [Luminar](https://skylum.com/luminar) - Luminar offers top-notch photo editing features 142- [Luminar](https://skylum.com/luminar) - Luminar offers top-notch photo
121- [Minecraft](https://www.minecraft.net/) - Block mining simulator 143 editing features
122- [NetNewsWire](https://netnewswire.com/) - A free and open source RSS reader for Mac, iPhone, and iPad 144- [Minecraft](https://www.minecraft.net/) - Block mining simulator
123- [Plex](https://www.plex.tv/) (`*`) - Desktop client for the Plex Media Server 145- [NetNewsWire](https://netnewswire.com/) - A free and open source RSS reader
124- [Steam](https://store.steampowered.com/) - The top gaming marketplace for computers 146 for Mac, iPhone, and iPad
125- [Transmission](https://transmissionbt.com/) (`*`) - A Fast, Easy and Free Bittorrent Client 147- [Plex](https://www.plex.tv/) (`*`) - Desktop client for the Plex Media
126- [VLC](https://www.videolan.org/vlc/) - A free and open source cross-platform multimedia player 148 Server
149- [Steam](https://store.steampowered.com/) - The top gaming marketplace for
150 computers
151- [Transmission](https://transmissionbt.com/) (`*`) - A Fast, Easy and Free
152 Bittorrent Client
153- [VLC](https://www.videolan.org/vlc/) - A free and open source cross-platform
154 multimedia player
127 155
128### Package Management 156### Package Management
129 157
130- [Homebrew](https://brew.sh/) (`*`) - The Missing Package Manager for macOS (or Linux) 158- [Homebrew](https://brew.sh/) (`*`) - The Missing Package Manager for macOS
131- [MacPorts](https://www.macports.org/) - A system to compile, install, and manage open source software 159 (or Linux)
160- [MacPorts](https://www.macports.org/) - A system to compile, install, and
161 manage open source software
132 162
133### Utilities 163### Utilities
134 164
135- [Bartender 5](https://www.macbartender.com/Bartender5/) (`*`) - Easy control and customization over the native macOS menu bar 165- [Bartender 5](https://www.macbartender.com/Bartender5/) (`*`) - Easy control
136- [BetterDisplay](https://betterdisplay.pro/) - Allows you to tweak a ton of features of built-in and external screens, such as scaling, configuration overrides, and color/brightness upscaling 166 and customization over the native macOS menu bar
137- [Bitwarden](https://bitwarden.com/) - An open source password manager 167- [BetterDisplay](https://betterdisplay.pro/) - Allows you to tweak a ton of
138- [LittleSnitch](https://obdev.at/products/littlesnitch/index.html) - Shows all network connections on your Macbook, including system and privileged services 168 features of built-in and external screens, such as scaling, configuration
139- [MicroSnitch](https://obdev.at/products/microsnitch/index.html) - Camera & microphone monitoring and alterting service 169 overrides, and color/brightness upscaling
140- [Mullvad](https://mullvad.net/) (`*`) - A private VPN service 170- [Bitwarden](https://bitwarden.com/) - An open source password manager
141- [Ollama](https://ollama.com/) - Run Llama 2, Code Llama, and other models locally on your machine 171- [LittleSnitch](https://obdev.at/products/littlesnitch/index.html) - Shows
142 - [Ollama Swift](https://github.com/kghandour/Ollama-SwiftUI) - User Interface made for Ollama.ai using Swift 172 all network connections on your Macbook, including system and privileged
143- [OrbStack](https://orbstack.dev/) - A fast and convenient GUI to manage Docker contains and Linux VMs 173 services
144- [Raycast](https://www.raycast.com/) - A collection of tools and shortcuts, an alternative to Spotlight 174- [MicroSnitch](https://obdev.at/products/microsnitch/index.html) - Camera &
145- [skhd](https://github.com/koekeishiya/skhd) (`*`) - Simple hotkey daemon for macOS 175 microphone monitoring and alterting service
146- [Strongbox](https://strongboxsafe.com/) - Keepass password manager for iOS & macOS 176- [Mullvad](https://mullvad.net/) (`*`) - A private VPN service
147- [Syncthing](https://syncthing.net/) (`*`) - Continuous file synchronization 177- [Ollama](https://ollama.com/) - Run Llama 2, Code Llama, and other models
148- [TinkerTool](https://www.bresink.com/osx/TinkerTool.html) - Unlock hidden configuration options for macOS 178 locally on your machine
149- [yabai](https://github.com/koekeishiya/yabai) (`*`) - Automatic window tiling 179 - [Ollama Swift](https://github.com/kghandour/Ollama-SwiftUI) - User
150- [yt-dlp](https://github.com/yt-dlp/yt-dlp) - A youtube-dl fork with additional features and fixes 180 Interface made for Ollama.ai using Swift
181- [OrbStack](https://orbstack.dev/) - A fast and convenient GUI to manage
182 Docker contains and Linux VMs
183- [Raycast](https://www.raycast.com/) - A collection of tools and shortcuts,
184 an alternative to Spotlight
185- [skhd](https://github.com/koekeishiya/skhd) (`*`) - Simple hotkey daemon for
186 macOS
187- [Strongbox](https://strongboxsafe.com/) - Keepass password manager for iOS &
188 macOS
189- [Syncthing](https://syncthing.net/) (`*`) - Continuous file synchronization
190- [TinkerTool](https://www.bresink.com/osx/TinkerTool.html) - Unlock hidden
191 configuration options for macOS
192- [yabai](https://github.com/koekeishiya/yabai) (`*`) - Automatic window
193 tiling
194- [yt-dlp](https://github.com/yt-dlp/yt-dlp) - A youtube-dl fork with
195 additional features and fixes
templates/base.html +12 −10
@@ -5,20 +5,21 @@
5 <title>cleberg.net</title> 5 <title>cleberg.net</title>
6 {% endblock %} 6 {% endblock %}
7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <meta name="theme-color" content="#111" media="(prefers-color-scheme: dark)"> 8 <meta name="theme-color" content="#111" media="(prefers-color-scheme:
9 <meta name="theme-color" content="#fff" media="(prefers-color-scheme: light)"> 9 dark)">
10 {% if page %} 10 <meta name="theme-color" content="#fff" media="(prefers-color-scheme:
11 {% if page.description %} 11 light)">
12 {% if page %} {% if page.description %}
12 <meta name="description" content="{{ page.description }}"> 13 <meta name="description" content="{{ page.description }}">
13 {% elif config.description %} 14 {% elif config.description %}
14 <meta name="description" content="{{ config.description }}"> 15 <meta name="description" content="{{ config.description }}">
15 {% endif %} 16 {% endif %} {% elif config.description %}
16 {% elif config.description %} 17 <meta name="description" content="{{ config.description }}" /> {% endif
17 <meta name="description" content="{{ config.description }}" /> 18 %}
18 {% endif %}
19 19
20 {% block rss %} 20 {% block rss %}
21 <link rel="alternate" type="application/atom+xml" title="RSS" href="{{ get_url(path="atom.xml", trailing_slash=false) }}"> 21 <link rel="alternate" type="application/atom+xml" title="RSS" href="{{
22 get_url(path="atom.xml", trailing_slash=false) }}">
22 {% endblock %} 23 {% endblock %}
23 24
24 {% block css %} 25 {% block css %}
@@ -41,7 +42,8 @@
41 42
42 <footer> 43 <footer>
43 <p>Last build: {{ now() | date(format="%Y-%m-%d %H:%M:%S") }}</p> 44 <p>Last build: {{ now() | date(format="%Y-%m-%d %H:%M:%S") }}</p>
44 <p><a href="https://git.cleberg.net/?p=cleberg.net.git;a=summary" target="_blank" rel="noopener">Source Code</a></p> 45 <p><a href="https://git.cleberg.net/?p=cleberg.net.git;a=summary"
46 target="_blank" rel="noopener">Source Code</a></p>
45 <p><a href="/atom.xml">Atom RSS Feed</a></p> 47 <p><a href="/atom.xml">Atom RSS Feed</a></p>
46 </footer> 48 </footer>
47</body> 49</body>
templates/blog.html +6 −4
@@ -3,15 +3,17 @@
3{% block content %} 3{% block content %}
4<h1>{{ section.title }}</h1> 4<h1>{{ section.title }}</h1>
5<p>Use <code>Ctrl + F</code> to search blog post titles for keywords.</p> 5<p>Use <code>Ctrl + F</code> to search blog post titles for keywords.</p>
6<p>You can also add the <a href="/atom.xml">Atom RSS Feed</a> to your feed reader.</p> 6<p>You can also add the <a href="/atom.xml">Atom RSS Feed</a> to your feed
7reader.</p>
7{% set post_date = "1970-01-01" | date(format="%Y") %} 8{% set post_date = "1970-01-01" | date(format="%Y") %}
8{% for page in section.pages %} 9{% for page in section.pages %}
9 {% if post_date != page.date | date(format="%Y") %} 10{% if post_date != page.date | date(format="%Y") %}
10 {% set_global post_date = page.date | date(format="%Y") %} 11{% set_global post_date = page.date | date(format="%Y") %}
11 <h2>{{ post_date }}</h2> 12 <h2>{{ post_date }}</h2>
12 {% endif %} 13 {% endif %}
13 <div class="post"> 14 <div class="post">
14 <time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S') }}">{{ page.date | date(format='%Y-%m-%d') }}</time> 15 <time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S') }}">{{
16 page.date | date(format='%Y-%m-%d') }}</time>
15 <a href="/blog/{{ page.slug }}/">{{ page.title }}</a> 17 <a href="/blog/{{ page.slug }}/">{{ page.title }}</a>
16 </div> 18 </div>
17{% endfor %} 19{% endfor %}
templates/index.html +9 −7
@@ -12,14 +12,14 @@ uid [ultimate] Christian Cleberg &lt;hello@cleberg.net&gt;</pre>
12 {% set section = get_section(path="blog/_index.md") %} 12 {% set section = get_section(path="blog/_index.md") %}
13 {% set i = 0 %} 13 {% set i = 0 %}
14 {% for page in section.pages %} 14 {% for page in section.pages %}
15 {% if i < 3%} 15 {% if i < 3%}
16 {% set_global i = i + 1%} 16 {% set_global i = i + 1%}
17 <div class="post"> 17 <div class="post">
18 <time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S') }}">{{ page.date | date(format='%Y-%m-%d') }}</time> 18 <time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S')
19 }}">{{ page.date | date(format='%Y-%m-%d') }}</time>
19 <a href="/blog/{{ page.slug }}/">{{ page.title }}</a> 20 <a href="/blog/{{ page.slug }}/">{{ page.title }}</a>
20 </div> 21 </div>
21 {% endif %} 22 {% endif %} {% endfor %}
22 {% endfor %}
23 <br> 23 <br>
24 <a href="/blog/">All Posts &rarr;</a> 24 <a href="/blog/">All Posts &rarr;</a>
25</section> 25</section>
@@ -35,8 +35,10 @@ uid [ultimate] Christian Cleberg &lt;hello@cleberg.net&gt;</pre>
35 <h2>Contact</h2> 35 <h2>Contact</h2>
36 <ul> 36 <ul>
37 <li>hello [at] cleberg.net (<a href="/gpg.txt">GPG</a>)</li> 37 <li>hello [at] cleberg.net (<a href="/gpg.txt">GPG</a>)</li>
38 <li><a href="https://matrix.to/#/@cyborg:matrix.tchncs.de" target="_blank" rel="noopener">@cyborg:@matrix.tchncs.de</a></li> 38 <li><a href="https://matrix.to/#/@cyborg:matrix.tchncs.de"
39 <li><a href="https://git.cleberg.net/" target="_blank" rel="noopener">Git</a></li> 39 target="_blank" rel="noopener">@cyborg:@matrix.tchncs.de</a></li>
40 <li><a href="https://git.cleberg.net/" target="_blank"
41 rel="noopener">Git</a></li>
40 </ul> 42 </ul>
41</section> 43</section>
42{% endblock content %} 44{% endblock content %}
templates/page.html +11 −7
@@ -5,8 +5,10 @@
5{% endblock %} 5{% endblock %}
6 6
7{% block css %} 7{% block css %}
8<link rel="stylesheet" href="/syntax-theme-dark.css" media="(prefers-color-scheme: dark)"> 8<link rel="stylesheet" href="/syntax-theme-dark.css"
9<link rel="stylesheet" href="/syntax-theme-light.css" media="(prefers-color-scheme: light)"> 9media="(prefers-color-scheme: dark)">
10<link rel="stylesheet" href="/syntax-theme-light.css"
11media="(prefers-color-scheme: light)">
10<link rel="stylesheet" href="/styles.css"> 12<link rel="stylesheet" href="/styles.css">
11{% endblock css %} 13{% endblock css %}
12 14
@@ -14,10 +16,11 @@
14<section class="post-metadata"> 16<section class="post-metadata">
15 <h1>{{ page.title }}</h1> 17 <h1>{{ page.title }}</h1>
16 {% if page.date %} 18 {% if page.date %}
17 <p><time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S') }}">{{ page.date }}</time></p> 19 <p><time datetime="{{ page.date | date(format='%Y-%m-%d %H:%M:%S') }}">{{
18 {% endif %} 20 page.date }}</time></p>
19 {% if page.updated %} 21 {% endif %} {% if page.updated %}
20 <p>Last Updated: <time datetime="{{ page.updated | date(format='%Y-%m-%d %H:%M:%S') }}">{{ page.updated }}</time></p> 22 <p>Last Updated: <time datetime="{{ page.updated | date(format='%Y-%m-%d
23 %H:%M:%S') }}">{{ page.updated }}</time></p>
21 {% endif %} 24 {% endif %}
22 <p>{{ page.word_count }} words; {{ page.reading_time }} minute(s)</p> 25 <p>{{ page.word_count }} words; {{ page.reading_time }} minute(s)</p>
23{% if page.toc %} 26{% if page.toc %}
@@ -32,7 +35,8 @@
32 <ul> 35 <ul>
33 {% for h2 in h1.children %} 36 {% for h2 in h1.children %}
34 <li> 37 <li>
35 <a href="{{ h2.permalink | safe }}">{{ h2.title }}</a> 38 <a href="{{ h2.permalink | safe }}">{{
39 h2.title }}</a>
36 </li> 40 </li>
37 {% endfor %} 41 {% endfor %}
38 </ul> 42 </ul>
templates/wiki.html +3 −3
@@ -10,7 +10,7 @@
10{% for page in section.pages %} 10{% for page in section.pages %}
11 <div class="wiki-post"> 11 <div class="wiki-post">
12 <p><a href="/wiki/{{ page.slug }}/">{{ page.title }}</a></p> 12 <p><a href="/wiki/{{ page.slug }}/">{{ page.title }}</a></p>
13 <time datetime="{{ page.updated | date(format='%Y-%m-%d %H:%M:%S') }}">{{ page.updated | date(format='%Y-%m-%d')}}</p> 13 <time datetime="{{ page.updated | date(format='%Y-%m-%d %H:%M:%S')
14 }}">{{ page.updated | date(format='%Y-%m-%d')}}</p>
14 </div> 15 </div>
15{% endfor %} 16{% endfor %} {% endblock content %}
16{% endblock content %}