Commit 3d70db647d
Unsigned
Layout: unified · split
content/blog/2024-01-08-dont-say-hello.org +16 −16
| @@ -3,25 +3,25 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: dont-say-hello | 4 | #+slug: dont-say-hello |
| 5 | 5 | ||
| 6 | I recently came back from a winter break and have started working | 6 | I recently came back from a winter break and have started working again... only |
| 7 | again... only to immediately run into the dilemma of people sending me | 7 | to immediately run into the dilemma of people sending me cliffhanger messages |
| 8 | cliffhanger messages again. | 8 | again. |
| 9 | 9 | ||
| 10 | * No Hello | 10 | * No Hello |
| 11 | 11 | ||
| 12 | A year or two ago, I discovered [[https://nohello.net/en/][no hello]] | 12 | A year or two ago, I discovered [[https://nohello.net/en/][no hello]] and have thought about it often since |
| 13 | and have thought about it often since then. I've even sent it to a few | 13 | then. I've even sent it to a few people since then (who wouldn't take offense to |
| 14 | people since then (who wouldn't take offense to it). | 14 | it). |
| 15 | 15 | ||
| 16 | I work in a fast-paced environment where efficiency is extremely | 16 | I work in a fast-paced environment where efficiency is extremely valuable. |
| 17 | valuable. Therefore, I have always held a deep displeasure for | 17 | Therefore, I have always held a deep displeasure for conversations where people |
| 18 | conversations where people start with "Hello" and then. | 18 | start with "Hello" and then. |
| 19 | 19 | ||
| 20 | I searched back through my work messages and found that I received ~50 | 20 | I searched back through my work messages and found that I received ~50 messages |
| 21 | messages from ~10 people last year from people that contained "hi", | 21 | from ~10 people last year from people that contained "hi", "hey", or "hello" and |
| 22 | "hey", or "hello" and did not contain any indication of the purpose of | 22 | did not contain any indication of the purpose of the conversation. I also |
| 23 | the conversation. I also noticed that a few of the users were | 23 | noticed that a few of the users were responsible for the large majority of the |
| 24 | responsible for the large majority of the cliffhangers. | 24 | cliffhangers. |
| 25 | 25 | ||
| 26 | There's no real point to this post, just a desparate request for people | 26 | There's no real point to this post, just a desparate request for people to |
| 27 | to please stop doing this. | 27 | please stop doing this. |
content/blog/2024-01-09-macos-customization.org +52 −68
| @@ -3,73 +3,65 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: macos-customization | 4 | #+slug: macos-customization |
| 5 | 5 | ||
| 6 | I have been using macOS more than Linux lately, so I wrote this post to | 6 | I have been using macOS more than Linux lately, so I wrote this post to describe |
| 7 | describe some simple options to customize macOS beyond the normal | 7 | some simple options to customize macOS beyond the normal built-in settings menu. |
| 8 | built-in settings menu. | ||
| 9 | 8 | ||
| 10 | While not all-encompassing, the options below should be a good start for | 9 | While not all-encompassing, the options below should be a good start for anyone |
| 11 | anyone looking to dive down the rabbit hole. | 10 | looking to dive down the rabbit hole. |
| 12 | 11 | ||
| 13 | * Basics | 12 | * Basics |
| 14 | 13 | ||
| 15 | ** Package Management | 14 | ** Package Management |
| 16 | 15 | ||
| 17 | To install a lot of software on macOS, you will need | 16 | To install a lot of software on macOS, you will need [[https://brew.sh/][Homebrew]]. You can use their |
| 18 | [[https://brew.sh/][Homebrew]]. You can use their installation script to | 17 | installation script to get started. Simply open the =Terminal= application and |
| 19 | get started. Simply open the =Terminal= application and paste the | 18 | paste the following snippet: |
| 20 | following snippet: | ||
| 21 | 19 | ||
| 22 | #+begin_src sh | 20 | #+begin_src sh |
| 23 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | 21 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
| 24 | #+end_src | 22 | #+end_src |
| 25 | 23 | ||
| 26 | This will allow you to easily install and manage applications and other | 24 | This will allow you to easily install and manage applications and other software |
| 27 | software easily through the =brew= command. | 25 | easily through the =brew= command. |
| 28 | 26 | ||
| 29 | ** Terminal | 27 | ** Terminal |
| 30 | 28 | ||
| 31 | If you're serious about customizing your macOS system, I highly | 29 | If you're serious about customizing your macOS system, I highly recommend |
| 32 | recommend installing a terminal emulator that you like and if you're not | 30 | installing a terminal emulator that you like and if you're not comfortable on |
| 33 | comfortable on the command line yet, start learning. A lot of | 31 | the command line yet, start learning. A lot of customization options require you |
| 34 | customization options require you to edit hidden files, which is easiest | 32 | to edit hidden files, which is easiest in a terminal. |
| 35 | in a terminal. | ||
| 36 | 33 | ||
| 37 | There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the | 34 | There are options like iTerm2, Kitty, Alacritty, Hyper, Warp, or the built-in |
| 38 | built-in Terminal app. | 35 | Terminal app. |
| 39 | 36 | ||
| 40 | I use [[https://iterm2.com/][iTerm2]], which can be installed with | 37 | I use [[https://iterm2.com/][iTerm2]], which can be installed with Homebrew: |
| 41 | Homebrew: | ||
| 42 | 38 | ||
| 43 | #+begin_src sh | 39 | #+begin_src sh |
| 44 | brew install iterm2 | 40 | brew install iterm2 |
| 45 | #+end_src | 41 | #+end_src |
| 46 | 42 | ||
| 47 | To install color schemes, such as the Dracula scheme, you visit | 43 | To install color schemes, such as the Dracula scheme, you visit [[https://iterm2colorschemes.com/][iTerm Themes]] and |
| 48 | [[https://iterm2colorschemes.com/][iTerm Themes]] and follow their | 44 | follow their installation instructions to install any of the themes. |
| 49 | installation instructions to install any of the themes. | ||
| 50 | 45 | ||
| 51 | * Desktop | 46 | * Desktop |
| 52 | 47 | ||
| 53 | ** Window Management | 48 | ** Window Management |
| 54 | 49 | ||
| 55 | [[https://github.com/koekeishiya/yabai][yabai]] is a tiling window | 50 | [[https://github.com/koekeishiya/yabai][yabai]] is a tiling window manager for macOS. While other window managers exist, I |
| 56 | manager for macOS. While other window managers exist, I found that most | 51 | found that most of them struggled to create logical layouts and to allow me to |
| 57 | of them struggled to create logical layouts and to allow me to easily | 52 | easily move windows around the screen. |
| 58 | move windows around the screen. | ||
| 59 | 53 | ||
| 60 | Some advanced settings for yabai are only available if partially disable | 54 | Some advanced settings for yabai are only available if partially disable System |
| 61 | System Integrity Protection (SIP). However, I chose not to do this and | 55 | Integrity Protection (SIP). However, I chose not to do this and it hasn't |
| 62 | it hasn't affected my basic usage of yabai at all. | 56 | affected my basic usage of yabai at all. |
| 63 | 57 | ||
| 64 | Refer to the | 58 | Refer to the [[https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)][yabai wiki]] for installation instructions. You will need to ensure |
| 65 | [[https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release)][yabai | 59 | that yabai is allowed to access the accessibility and screen recording APIs. |
| 66 | wiki]] for installation instructions. You will need to ensure that yabai | ||
| 67 | is allowed to access the accessibility and screen recording APIs. | ||
| 68 | 60 | ||
| 69 | ** Keyboard Shortcuts | 61 | ** Keyboard Shortcuts |
| 70 | 62 | ||
| 71 | [[https://github.com/koekeishiya/skhd][skhd]] is a simple hotkey daemon | 63 | [[https://github.com/koekeishiya/skhd][skhd]] is a simple hotkey daemon that allows you to define hotkeys in a file for |
| 72 | that allows you to define hotkeys in a file for usage on your system. | 64 | usage on your system. |
| 73 | 65 | ||
| 74 | Installation is simple: | 66 | Installation is simple: |
| 75 | 67 | ||
| @@ -78,8 +70,8 @@ brew install koekeishiya/formulae/skhd | |||
| 78 | skhd --start-service | 70 | skhd --start-service |
| 79 | #+end_src | 71 | #+end_src |
| 80 | 72 | ||
| 81 | After installation, be sure to allow =skhd= access to the accessibility | 73 | After installation, be sure to allow =skhd= access to the accessibility API in |
| 82 | API in the macOS privacy settings. | 74 | the macOS privacy settings. |
| 83 | 75 | ||
| 84 | You can configure your hotkeys in the =~/.config/skhd/skhdrc= file: | 76 | You can configure your hotkeys in the =~/.config/skhd/skhdrc= file: |
| 85 | 77 | ||
| @@ -99,53 +91,45 @@ cmd + shift - return : /Applications/LibreWolf.app/Contents/MacOS/librewolf | |||
| 99 | 91 | ||
| 100 | ** Widgets | 92 | ** Widgets |
| 101 | 93 | ||
| 102 | [[https://github.com/felixhageloh/uebersicht/][uebersicht]] is a handy | 94 | [[https://github.com/felixhageloh/uebersicht/][uebersicht]] is a handy desktop-based widget tool with a plethora of |
| 103 | desktop-based widget tool with a plethora of community-made widgets | 95 | community-made widgets available in the [[https://tracesof.net/uebersicht-widgets/][widgets gallery]]. You can also write your |
| 104 | available in the [[https://tracesof.net/uebersicht-widgets/][widgets | 96 | own widgets with this tool. |
| 105 | gallery]]. You can also write your own widgets with this tool. | ||
| 106 | 97 | ||
| 107 | To install, simply download the latest release from the | 98 | To install, simply download the latest release from the [[https://tracesof.net/uebersicht/][uebersicht website]] and |
| 108 | [[https://tracesof.net/uebersicht/][uebersicht website]] and copy it to | 99 | copy it to the Applications folder. |
| 109 | the Applications folder. | ||
| 110 | 100 | ||
| 111 | See below for an example of the | 101 | See below for an example of the [[https://tracesof.net/uebersicht-widgets/#Mond][Mond]] widget in action. |
| 112 | [[https://tracesof.net/uebersicht-widgets/#Mond][Mond]] widget in | ||
| 113 | action. | ||
| 114 | 102 | ||
| 115 | ** Status Bar | 103 | ** Status Bar |
| 116 | 104 | ||
| 117 | [[https://github.com/FelixKratz/SketchyBar][SketchyBar]] is a | 105 | [[https://github.com/FelixKratz/SketchyBar][SketchyBar]] is a customizable replacement for the macOS status or menu bar. |
| 118 | customizable replacement for the macOS status or menu bar. | ||
| 119 | 106 | ||
| 120 | You can browse a discussion where various users shared their | 107 | You can browse a discussion where various users shared their [[https://github.com/FelixKratz/SketchyBar/discussions/47?sort=top][configurations]] for |
| 121 | [[https://github.com/FelixKratz/SketchyBar/discussions/47?sort=top][configurations]] | 108 | inspiration or to copy their dotfiles. |
| 122 | for inspiration or to copy their dotfiles. | ||
| 123 | 109 | ||
| 124 | ** Dock | 110 | ** Dock |
| 125 | 111 | ||
| 126 | The easiest way to customize the dock is to install | 112 | The easiest way to customize the dock is to install [[https://ubarapp.com/][uBar]], which uses a |
| 127 | [[https://ubarapp.com/][uBar]], which uses a Windows-like menu bar as | 113 | Windows-like menu bar as the default style. |
| 128 | the default style. | ||
| 129 | 114 | ||
| 130 | However, the built-in macOS dock cannot be disabled and can only be set | 115 | However, the built-in macOS dock cannot be disabled and can only be set to |
| 131 | to "always hidden". This can be annoying as it will pop out any time | 116 | "always hidden". This can be annoying as it will pop out any time your mouse |
| 132 | your mouse cursor passes closely to the dock edge of the screen. Because | 117 | cursor passes closely to the dock edge of the screen. Because of this, I simply |
| 133 | of this, I simply use the built-in dock instead of customizing it with | 118 | use the built-in dock instead of customizing it with third-party software. |
| 134 | third-party software. | ||
| 135 | 119 | ||
| 136 | Regardless, see below for the default installation style of uBar. | 120 | Regardless, see below for the default installation style of uBar. |
| 137 | 121 | ||
| 138 | ** Application Icons | 122 | ** Application Icons |
| 139 | 123 | ||
| 140 | You can also customize the icon of any application in macOS, which will | 124 | You can also customize the icon of any application in macOS, which will show up |
| 141 | show up in Finder, the Dock, Launchpad, search results, etc. I recommend | 125 | in Finder, the Dock, Launchpad, search results, etc. I recommend using |
| 142 | using [[https://macosicons.com/][macOSicons]] to download icons you | 126 | [[https://macosicons.com/][macOSicons]] to download icons you want, and then apply them by following this |
| 143 | want, and then apply them by following this process. | 127 | process. |
| 144 | 128 | ||
| 145 | 1. Open the Finder application. | 129 | 1. Open the Finder application. |
| 146 | 2. Navigate to the =Applications= folder. | 130 | 2. Navigate to the =Applications= folder. |
| 147 | 3. Right-click an application of your choice, and select =Get Info=. | 131 | 3. Right-click an application of your choice, and select =Get Info=. |
| 148 | 4. Drag the image you downloaded on top of the application's icon at the | 132 | 4. Drag the image you downloaded on top of the application's icon at the top of |
| 149 | top of information window (you will see a green "plus" symbol when | 133 | information window (you will see a green "plus" symbol when you're hovering |
| 150 | you're hovering over it). | 134 | over it). |
| 151 | 5. Release the new icon on top of the old icon and it will update! | 135 | 5. Release the new icon on top of the old icon and it will update! |
content/blog/2024-01-13-local-llm.org +43 −51
| @@ -5,11 +5,10 @@ | |||
| 5 | 5 | ||
| 6 | * Requirements | 6 | * Requirements |
| 7 | 7 | ||
| 8 | I've recently started playing with large language models (LLMs), mostly | 8 | I've recently started playing with large language models (LLMs), mostly in the |
| 9 | in the popular chatbot form, as part of my job and have decided to see | 9 | popular chatbot form, as part of my job and have decided to see if there's a |
| 10 | if there's a consistent and reliable way to interact with these models | 10 | consistent and reliable way to interact with these models on Apple devices |
| 11 | on Apple devices without sacrificing privacy or requiring in-depth | 11 | without sacrificing privacy or requiring in-depth technical setup. |
| 12 | technical setup. | ||
| 13 | 12 | ||
| 14 | My requirements for this test: | 13 | My requirements for this test: |
| 15 | 14 | ||
| @@ -18,12 +17,12 @@ My requirements for this test: | |||
| 18 | - Minimal required configuration | 17 | - Minimal required configuration |
| 19 | - Preferably pre-built, but a simple build process is acceptable | 18 | - Preferably pre-built, but a simple build process is acceptable |
| 20 | 19 | ||
| 21 | I tested a handful of apps and have summarized my favorite (so far) for | 20 | I tested a handful of apps and have summarized my favorite (so far) for macOS |
| 22 | macOS and iOS below. | 21 | and iOS below. |
| 23 | 22 | ||
| 24 | #+begin_quote | 23 | #+begin_quote |
| 25 | TL;DR - Here are the two that met my requirements and I have found the | 24 | TL;DR - Here are the two that met my requirements and I have found the easiest |
| 26 | easiest to install and use so far: | 25 | to install and use so far: |
| 27 | #+end_quote | 26 | #+end_quote |
| 28 | 27 | ||
| 29 | - macOS: [[https://ollama.ai/][Ollama]] | 28 | - macOS: [[https://ollama.ai/][Ollama]] |
| @@ -31,13 +30,12 @@ easiest to install and use so far: | |||
| 31 | 30 | ||
| 32 | * macOS | 31 | * macOS |
| 33 | 32 | ||
| 34 | [[https://ollama.ai/][Ollama]] is a simple Go application for macOS and | 33 | [[https://ollama.ai/][Ollama]] is a simple Go application for macOS and Linux that can run various LLMs |
| 35 | Linux that can run various LLMs locally. | 34 | locally. |
| 36 | 35 | ||
| 37 | For macOS, you can download the pplication on the | 36 | For macOS, you can download the pplication on the [[https://ollama.ai/download/mac][Ollama download page]] and |
| 38 | [[https://ollama.ai/download/mac][Ollama download page]] and install it | 37 | install it by unzipping the =Ollama.app= file and moving it to the |
| 39 | by unzipping the =Ollama.app= file and moving it to the =Applications= | 38 | =Applications= folder. |
| 40 | folder. | ||
| 41 | 39 | ||
| 42 | If you prefer the command line, you can run these commands after the | 40 | If you prefer the command line, you can run these commands after the |
| 43 | download finished: | 41 | download finished: |
| @@ -48,49 +46,43 @@ unzip Ollama-darwin.zip && \ | |||
| 48 | mv ~/Downloads/Ollama.app /Applications/ | 46 | mv ~/Downloads/Ollama.app /Applications/ |
| 49 | #+end_src | 47 | #+end_src |
| 50 | 48 | ||
| 51 | After running the app, the app will ask you to open a terminal and run | 49 | After running the app, the app will ask you to open a terminal and run the |
| 52 | the default =llama2= model, which will open an interactive chat session | 50 | default =llama2= model, which will open an interactive chat session in the |
| 53 | in the terminal. You can startfully using the application at this point. | 51 | terminal. You can startfully using the application at this point. |
| 54 | 52 | ||
| 55 | If you don't want to use the default =llama2= model, you can download | 53 | If you don't want to use the default =llama2= model, you can download and run |
| 56 | and run additional models found on the | 54 | additional models found on the [[https://ollama.ai/library][Models]] page. |
| 57 | [[https://ollama.ai/library][Models]] page. | ||
| 58 | 55 | ||
| 59 | To see the information for the currently-used model, you can run the | 56 | To see the information for the currently-used model, you can run the |
| 60 | =/show info= command in the chat. | 57 | =/show info= command in the chat. |
| 61 | 58 | ||
| 62 | ** Community Integrations | 59 | ** Community Integrations |
| 63 | 60 | ||
| 64 | I highly recommend browsing the | 61 | I highly recommend browsing the [[https://github.com/jmorganca/ollama#community-integrations][Community Integrations]] section of the project to |
| 65 | [[https://github.com/jmorganca/ollama#community-integrations][Community | 62 | see how you would prefer to extend Ollama beyond a simple command-line |
| 66 | Integrations]] section of the project to see how you would prefer to | 63 | interface. There are options for APIs, browser UIs, advanced terminal |
| 67 | extend Ollama beyond a simple command-line interface. There are options | 64 | configurations, and more. |
| 68 | for APIs, browser UIs, advanced terminal configurations, and more. | ||
| 69 | 65 | ||
| 70 | * iOS | 66 | * iOS |
| 71 | 67 | ||
| 72 | While there are a handful of decent macOS options, it was quite | 68 | While there are a handful of decent macOS options, it was quite difficult to |
| 73 | difficult to find an iOS app that offered an open source platform | 69 | find an iOS app that offered an open source platform without an extensive |
| 74 | without an extensive configuration and building process. I found LLM | 70 | configuration and building process. I found LLM Farm to be decent enough in |
| 75 | Farm to be decent enough in quality to sit at the top of my list - | 71 | quality to sit at the top of my list - however, it's definitely not user |
| 76 | however, it's definitely not user friendly enough for me to consider | 72 | friendly enough for me to consider using it on a daily basis. |
| 77 | using it on a daily basis. | 73 | |
| 78 | 74 | [[https://llmfarm.site/][LLM Farm]] is available on TestFlight, so there's no manual build process | |
| 79 | [[https://llmfarm.site/][LLM Farm]] is available on TestFlight, so | 75 | required. However, you can view the [[https://github.com/guinmoon/LLMFarm][LLMFarm repository]] if you wish. |
| 80 | there's no manual build process required. However, you can view the | 76 | |
| 81 | [[https://github.com/guinmoon/LLMFarm][LLMFarm repository]] if you wish. | 77 | The caveat is that you will have to manually download the model files from the |
| 82 | 78 | links in the [[https://github.com/guinmoon/LLMFarm/blob/main/models.md][models.md]] file to your iPhone to use the app - there's currently no | |
| 83 | The caveat is that you will have to manually download the model files | 79 | option in the app to reach out and grab the latest version of any supported |
| 84 | from the links in the | 80 | model. |
| 85 | [[https://github.com/guinmoon/LLMFarm/blob/main/models.md][models.md]] | 81 | |
| 86 | file to your iPhone to use the app - there's currently no option in the | 82 | Once you have a file downloaded, you simply create a new chat and select the |
| 87 | app to reach out and grab the latest version of any supported model. | 83 | downloaded model file and ensure the inference matches the requirement in the |
| 88 | 84 | =models.md= file. | |
| 89 | Once you have a file downloaded, you simply create a new chat and select | 85 | |
| 90 | the downloaded model file and ensure the inference matches the | 86 | [[https://github.com/AugustDev/enchanted][Enchanted]] is also an iOS for private AI models, but it requires a public-facing |
| 91 | requirement in the =models.md= file. | 87 | Ollama API, which did not meet my "on device requirement." Nonetheless, it's an |
| 92 | 88 | interesting looking app and I will likely set it up to test soon. | |
| 93 | [[https://github.com/AugustDev/enchanted][Enchanted]] is also an iOS for | ||
| 94 | private AI models, but it requires a public-facing Ollama API, which did | ||
| 95 | not meet my "on device requirement." Nonetheless, it's an interesting | ||
| 96 | looking app and I will likely set it up to test soon. | ||
content/blog/2024-01-26-audit-dashboard.org +59 −64
| @@ -3,9 +3,9 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: audit-dashboard | 4 | #+slug: audit-dashboard |
| 5 | 5 | ||
| 6 | Alteryx and Power BI are powerful tools that can help turn your | 6 | Alteryx and Power BI are powerful tools that can help turn your old-school audit |
| 7 | old-school audit trackers into interactive tools that provide useful | 7 | trackers into interactive tools that provide useful insights and potential |
| 8 | insights and potential action plans. | 8 | action plans. |
| 9 | 9 | ||
| 10 | With these tools, we are going to build a dashboard that can effectively | 10 | With these tools, we are going to build a dashboard that can effectively |
| 11 | communicate project status. | 11 | communicate project status. |
| @@ -15,30 +15,28 @@ communicate project status. | |||
| 15 | This project assumes the following: | 15 | This project assumes the following: |
| 16 | 16 | ||
| 17 | - You have access to Alteryx Designer and Power BI Desktop. | 17 | - You have access to Alteryx Designer and Power BI Desktop. |
| 18 | - If you only have Power BI Desktop, you may need to perform some | 18 | - If you only have Power BI Desktop, you may need to perform some analysis in |
| 19 | analysis in Power BI instead of Alteryx. | 19 | Power BI instead of Alteryx. |
| 20 | - Your data is in a format that can be imported into Alteryx and/or | 20 | - Your data is in a format that can be imported into Alteryx and/or Power BI. |
| 21 | Power BI. | ||
| 22 | - You have a basic understanding of data types and visualization. | 21 | - You have a basic understanding of data types and visualization. |
| 23 | 22 | ||
| 24 | * Alteryx: Data Preparation & Analysis | 23 | * Alteryx: Data Preparation & Analysis |
| 25 | 24 | ||
| 26 | ** Import Data | 25 | ** Import Data |
| 27 | 26 | ||
| 28 | With Alteryx, importing data is easy with the use of the =Input Data= | 27 | With Alteryx, importing data is easy with the use of the =Input Data= tool. |
| 29 | tool. Simply drag this tool onto the canvas from the =In/Out= tab in the | 28 | Simply drag this tool onto the canvas from the =In/Out= tab in the Ribbon to |
| 30 | Ribbon to create it as a node. | 29 | create it as a node. |
| 31 | 30 | ||
| 32 | You can choose the File Format manually or simply connect to your | 31 | You can choose the File Format manually or simply connect to your file/database |
| 33 | file/database and let Alteryx determine the format for you. For this | 32 | and let Alteryx determine the format for you. For this example, we will be |
| 34 | example, we will be importing an Excel file and changing the | 33 | importing an Excel file and changing the =Start Data Import on Line= variable to |
| 35 | =Start Data Import on Line= variable to =2=. | 34 | =2=. |
| 36 | 35 | ||
| 37 | ** Transform Data | 36 | ** Transform Data |
| 38 | 37 | ||
| 39 | Next, let's replace null data and remove whitespace to clean up our | 38 | Next, let's replace null data and remove whitespace to clean up our data. We can |
| 40 | data. We can do this with the =Data Cleansing= tool in the =Preparation= | 39 | do this with the =Data Cleansing= tool in the =Preparation= tab in the Ribbon. |
| 41 | tab in the Ribbon. | ||
| 42 | 40 | ||
| 43 | Ensure that the following options are enabled: | 41 | Ensure that the following options are enabled: |
| 44 | 42 | ||
| @@ -48,49 +46,48 @@ Ensure that the following options are enabled: | |||
| 48 | - Remove Unwanted Characters | 46 | - Remove Unwanted Characters |
| 49 | - Leading and Trailing Whitespace | 47 | - Leading and Trailing Whitespace |
| 50 | 48 | ||
| 51 | For our next step, we will transform the date fields from strings to | 49 | For our next step, we will transform the date fields from strings to datetime |
| 52 | datetime format. Add a =Datetime= tool for each field you want to | 50 | format. Add a =Datetime= tool for each field you want to transform - in the |
| 53 | transform - in the example below, I am using the tool twice for the | 51 | example below, I am using the tool twice for the "Started On" and "Submitted On" |
| 54 | "Started On" and "Submitted On" fields. | 52 | fields. |
| 55 | 53 | ||
| 56 | Now that the dates are in the correct format, let's perform a | 54 | Now that the dates are in the correct format, let's perform a calculation based |
| 57 | calculation based on those fields. Start by adding a =Filter= tool, | 55 | on those fields. Start by adding a =Filter= tool, naming a new Output Column, |
| 58 | naming a new Output Column, and pasting the formula below into it (the | 56 | and pasting the formula below into it (the two fields used in this formula must |
| 59 | two fields used in this formula must match the output of the =Datetime= | 57 | match the output of the =Datetime= tools above): |
| 60 | tools above): | ||
| 61 | 58 | ||
| 62 | ``=txt DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days")= | 59 | ```txt |
| 60 | DateTimeDiff([SubmittedOn_Out],[StartedOn_Out], "days") | ||
| 61 | ``` | ||
| 63 | 62 | ||
| 64 | ** Export Data | 63 | ** Export Data |
| 65 | 64 | ||
| 66 | Finalize the process by exporting the transformed data set to a new | 65 | Finalize the process by exporting the transformed data set to a new file, for |
| 67 | file, for use in the following visualization step. | 66 | use in the following visualization step. |
| 68 | 67 | ||
| 69 | * Power BI: Data Visualization | 68 | * Power BI: Data Visualization |
| 70 | 69 | ||
| 71 | ** Import Data | 70 | ** Import Data |
| 72 | 71 | ||
| 73 | To start, open the Power BI Desktop application. Upon first use, Power | 72 | To start, open the Power BI Desktop application. Upon first use, Power BI will |
| 74 | BI will ask if you want to open an existing dashboard or import new | 73 | ask if you want to open an existing dashboard or import new data. |
| 75 | data. | ||
| 76 | 74 | ||
| 77 | As we are creating our first dashboard, let's import our data. In my | 75 | As we are creating our first dashboard, let's import our data. In my example |
| 78 | example below, I'm importing data from the "Tracker" sheet of the Excel | 76 | below, I'm importing data from the "Tracker" sheet of the Excel file I'm using |
| 79 | file I'm using for this project. | 77 | for this project. |
| 80 | 78 | ||
| 81 | During this process, I also imported the export from the Alteryx | 79 | During this process, I also imported the export from the Alteryx workflow above. |
| 82 | workflow above. Therefore, we have two different files available for use | 80 | Therefore, we have two different files available for use in our dashboard. |
| 83 | in our dashboard. | ||
| 84 | 81 | ||
| 85 | ** Add Visuals | 82 | ** Add Visuals |
| 86 | 83 | ||
| 87 | To create the dashboard, you will need to follow the list instructions | 84 | To create the dashboard, you will need to follow the list instructions below and |
| 88 | below and format as needed. | 85 | format as needed. |
| 89 | 86 | ||
| 90 | Instructions to create the visuals above: | 87 | Instructions to create the visuals above: |
| 91 | 88 | ||
| 92 | - =Text Box=: Explain the name and purpose of the dashboard. You can | 89 | - =Text Box=: Explain the name and purpose of the dashboard. You can also add |
| 93 | also add images and logos at the top of the dashboard. | 90 | images and logos at the top of the dashboard. |
| 94 | - =Donut Chart=: Overall status of the project. | 91 | - =Donut Chart=: Overall status of the project. |
| 95 | - =Legend=: Status | 92 | - =Legend=: Status |
| 96 | - =Values=: Count of Status | 93 | - =Values=: Count of Status |
| @@ -111,13 +108,12 @@ Instructions to create the visuals above: | |||
| 111 | 108 | ||
| 112 | ** Format the Dashboard | 109 | ** Format the Dashboard |
| 113 | 110 | ||
| 114 | You can choose a theme in the View tab of the Ribbon. You can even | 111 | You can choose a theme in the View tab of the Ribbon. You can even browse for |
| 115 | browse for custom JSON files that define themes, such as ones found | 112 | custom JSON files that define themes, such as ones found online or custom ones |
| 116 | online or custom ones created by your organization. | 113 | created by your organization. |
| 117 | 114 | ||
| 118 | For each visual, you can click the =Format= button in the | 115 | For each visual, you can click the =Format= button in the =Visualizations= side |
| 119 | =Visualizations= side pane and explore the options. You can custom | 116 | pane and explore the options. You can custom options such as: |
| 120 | options such as: | ||
| 121 | 117 | ||
| 122 | - Visual | 118 | - Visual |
| 123 | - Legend | 119 | - Legend |
| @@ -132,22 +128,21 @@ options such as: | |||
| 132 | - Tooltips | 128 | - Tooltips |
| 133 | - Alt text | 129 | - Alt text |
| 134 | 130 | ||
| 135 | You can always look online for inspiration when trying to decide how | 131 | You can always look online for inspiration when trying to decide how best to |
| 136 | best to organize and style your dashboard. | 132 | organize and style your dashboard. |
| 137 | 133 | ||
| 138 | * Sharing the Results | 134 | * Sharing the Results |
| 139 | 135 | ||
| 140 | Generally, you have a few different options for sharing your dashboards | 136 | Generally, you have a few different options for sharing your dashboards with |
| 141 | with others: | 137 | others: |
| 142 | 138 | ||
| 143 | 1. Export the dashboard as a PDF in the file menu of Power BI. This will | 139 | 1. Export the dashboard as a PDF in the file menu of Power BI. This will export |
| 144 | export all tabs and visuals as they are set when the export button is | 140 | all tabs and visuals as they are set when the export button is pressed. You |
| 145 | pressed. You will lose all interactivity with this option. | 141 | will lose all interactivity with this option. |
| 146 | 2. Send the full Power BI file to those you wish to share the dashboard. | 142 | 2. Send the full Power BI file to those you wish to share the dashboard. This |
| 147 | This will retain all settings and interactivity. However, you will | 143 | will retain all settings and interactivity. However, you will also need to |
| 148 | also need to send the source files if they need to refresh the | 144 | send the source files if they need to refresh the dashboard and you will need |
| 149 | dashboard and you will need to re-send the files if you make updates. | 145 | to re-send the files if you make updates. |
| 150 | 3. Store the dashboard in a synced location, such as a shared drive or | 146 | 3. Store the dashboard in a synced location, such as a shared drive or Microsoft |
| 151 | Microsoft Teams. Depending on how a user configures their local | 147 | Teams. Depending on how a user configures their local Windows paths, the data |
| 152 | Windows paths, the data source paths may not be compatible for all | 148 | source paths may not be compatible for all users with such a setup. |
| 153 | users with such a setup. | ||
content/blog/2024-01-27-tableau-dashboard.org +42 −47
| @@ -3,14 +3,12 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: tableau-dashboard | 4 | #+slug: tableau-dashboard |
| 5 | 5 | ||
| 6 | In this project, I am going to show you how to use Tableau Public for | 6 | In this project, I am going to show you how to use Tableau Public for free to |
| 7 | free to create simple dashboards. | 7 | create simple dashboards. |
| 8 | 8 | ||
| 9 | I will be creating simple visuals from an Omaha crime data set and | 9 | I will be creating simple visuals from an Omaha crime data set and combining |
| 10 | combining them to create the dashboard below. You can view this | 10 | them to create the dashboard below. You can view this dashboard interactively |
| 11 | dashboard interactively online here: | 11 | online here: [[https://public.tableau.com/app/profile/c.c7042/viz/OmahaCrimeData2015-2023/OmahaCrimeData2015-2023#1][Omaha Crime Data (2015 - 2023)]]. |
| 12 | [[https://public.tableau.com/app/profile/c.c7042/viz/OmahaCrimeData2015-2023/OmahaCrimeData2015-2023#1][Omaha | ||
| 13 | Crime Data (2015 - 2023)]]. | ||
| 14 | 12 | ||
| 15 | #+caption: Tableau Dashboard | 13 | #+caption: Tableau Dashboard |
| 16 | [[https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png]] | 14 | [[https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png]] |
| @@ -18,18 +16,17 @@ Crime Data (2015 - 2023)]]. | |||
| 18 | * Gather the Data | 16 | * Gather the Data |
| 19 | 17 | ||
| 20 | You can download incident data from the Omaha Police Department on their | 18 | You can download incident data from the Omaha Police Department on their |
| 21 | [[https://police.cityofomaha.org/crime-information/incident-data-download][Incident | 19 | [[https://police.cityofomaha.org/crime-information/incident-data-download][Incident Data Download]] page. They currently have files for the years 2015 |
| 22 | Data Download]] page. They currently have files for the years 2015 | ||
| 23 | through 2023. | 20 | through 2023. |
| 24 | 21 | ||
| 25 | Each file will be downloaded as a CSV file, approximately 3 MB - 8 MB. | 22 | Each file will be downloaded as a CSV file, approximately 3 MB - 8 MB. |
| 26 | 23 | ||
| 27 | * Clean and Transform the Data | 24 | * Clean and Transform the Data |
| 28 | 25 | ||
| 29 | I have used Python to combine the files into a single CSV file, as well | 26 | I have used Python to combine the files into a single CSV file, as well as |
| 30 | as adding a custom =datetime= column. You could do this step in any | 27 | adding a custom =datetime= column. You could do this step in any software you |
| 31 | software you prefer, but I prefer Python as its free, easy to use, and | 28 | prefer, but I prefer Python as its free, easy to use, and has a plethora of |
| 32 | has a plethora of support resources online. | 29 | support resources online. |
| 33 | 30 | ||
| 34 | Start by opening a terminal, navigating to your Downloads directory, and | 31 | Start by opening a terminal, navigating to your Downloads directory, and |
| 35 | creating a python script. | 32 | creating a python script. |
| @@ -76,38 +73,37 @@ Once pasted, save and close the file. You can execute the file like so: | |||
| 76 | python3 data_processing.py | 73 | python3 data_processing.py |
| 77 | #+end_src | 74 | #+end_src |
| 78 | 75 | ||
| 79 | After this, you should have a combined data file that contains all | 76 | After this, you should have a combined data file that contains all incidents |
| 80 | incidents between 2015 and 2023. Mine was approximately 55 MB. | 77 | between 2015 and 2023. Mine was approximately 55 MB. |
| 81 | 78 | ||
| 82 | * Tableau Public | 79 | * Tableau Public |
| 83 | 80 | ||
| 84 | [[https://public.tableau.com/][Tableau Public]] is a free-to-use web | 81 | [[https://public.tableau.com/][Tableau Public]] is a free-to-use web application that allows you to create |
| 85 | application that allows you to create visualizations by uploading data | 82 | visualizations by uploading data sources. Note that there's no way to keep the |
| 86 | sources. Note that there's no way to keep the data and visualizations | 83 | data and visualizations private, so don't upload anything private. |
| 87 | private, so don't upload anything private. | ||
| 88 | 84 | ||
| 89 | After creating an account, you can click the =Create= > =Web Authoring= | 85 | After creating an account, you can click the =Create= > =Web Authoring= link to |
| 90 | link to create your first visualization. | 86 | create your first visualization. |
| 91 | 87 | ||
| 92 | ** Upload the Data | 88 | ** Upload the Data |
| 93 | 89 | ||
| 94 | Once you've opened your first project, Tableau will ask you to connect | 90 | Once you've opened your first project, Tableau will ask you to connect to your |
| 95 | to your data. For this project, click the =Upload from computer= button | 91 | data. For this project, click the =Upload from computer= button and select the |
| 96 | and select the CSV file previously combined in the step above. | 92 | CSV file previously combined in the step above. |
| 97 | 93 | ||
| 98 | Once connected, you can refresh the preview of the data with the | 94 | Once connected, you can refresh the preview of the data with the =Refresh Data |
| 99 | =Refresh Data Source= button in the toolbar. | 95 | Source= button in the toolbar. |
| 100 | 96 | ||
| 101 | If you need to edit any of the data types, column names, etc., you can | 97 | If you need to edit any of the data types, column names, etc., you can do so |
| 102 | do so now. Once complete, generate an extract so that you can start | 98 | now. Once complete, generate an extract so that you can start creating |
| 103 | creating visualizations. | 99 | visualizations. |
| 104 | 100 | ||
| 105 | ** Create Visualizations | 101 | ** Create Visualizations |
| 106 | 102 | ||
| 107 | To start, create a worksheet in the toolbar at the bottom of the screen. | 103 | To start, create a worksheet in the toolbar at the bottom of the screen. |
| 108 | 104 | ||
| 109 | Within this screen, select a column from the =Data= side bar on the left | 105 | Within this screen, select a column from the =Data= side bar on the left and |
| 110 | and drag it into the =Columns= or =Rows= area of the canvas. | 106 | drag it into the =Columns= or =Rows= area of the canvas. |
| 111 | 107 | ||
| 112 | See below for the map visualization. You can recreate this by adding the | 108 | See below for the map visualization. You can recreate this by adding the |
| 113 | following fields: | 109 | following fields: |
| @@ -119,30 +115,29 @@ following fields: | |||
| 119 | - Datetime | 115 | - Datetime |
| 120 | - =Filters=: Datetime | 116 | - =Filters=: Datetime |
| 121 | 117 | ||
| 122 | You can repeat this process for each visualization you want to create. | 118 | You can repeat this process for each visualization you want to create. Explore |
| 123 | Explore your options by dragging data fields to different areas and by | 119 | your options by dragging data fields to different areas and by opening the field |
| 124 | opening the field options to explore what operations can be performed on | 120 | options to explore what operations can be performed on different data types |
| 125 | different data types (e.g., average, count, etc.). | 121 | (e.g., average, count, etc.). |
| 126 | 122 | ||
| 127 | ** Create Dashboard | 123 | ** Create Dashboard |
| 128 | 124 | ||
| 129 | To create a dashboard, click the button on the toolbar at the bottom of | 125 | To create a dashboard, click the button on the toolbar at the bottom of the |
| 130 | the screen. Within the dashboard, drag each sheet from the left side bar | 126 | screen. Within the dashboard, drag each sheet from the left side bar onto the |
| 131 | onto the dashboard canvas. | 127 | dashboard canvas. |
| 132 | 128 | ||
| 133 | ** Formatting | 129 | ** Formatting |
| 134 | 130 | ||
| 135 | You can explore a ton of different formatting options throughout the | 131 | You can explore a ton of different formatting options throughout the worksheets |
| 136 | worksheets and dashboard. Specifically for maps, you can alter the map | 132 | and dashboard. Specifically for maps, you can alter the map layers, background, |
| 137 | layers, background, and visible features through the =Map= menu in the | 133 | and visible features through the =Map= menu in the top file menu of the editing |
| 138 | top file menu of the editing screen. | 134 | screen. |
| 139 | 135 | ||
| 140 | In the finished dashboard below, I opted for a dark mode with a map that | 136 | In the finished dashboard below, I opted for a dark mode with a map that showed |
| 141 | showed county lines and city names. | 137 | county lines and city names. |
| 142 | 138 | ||
| 143 | There's a ton of other options available to be used in a dashboard like | 139 | There's a ton of other options available to be used in a dashboard like this, |
| 144 | this, but this project shows a quick preview of what you can do in | 140 | but this project shows a quick preview of what you can do in Tableau Public. |
| 145 | Tableau Public. | ||
| 146 | 141 | ||
| 147 | #+caption: Tableau Dashboard | 142 | #+caption: Tableau Dashboard |
| 148 | [[https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png]] | 143 | [[https://img.cleberg.net/blog/20240127-tableau-dashboard/dashboard.png]] |
content/blog/2024-02-06-zfs.org +54 −68
| @@ -6,14 +6,11 @@ | |||
| 6 | This post details the process I used to create ZFS pools, datasets, and | 6 | This post details the process I used to create ZFS pools, datasets, and |
| 7 | snapshots on Ubuntu Server. | 7 | snapshots on Ubuntu Server. |
| 8 | 8 | ||
| 9 | I found the following pages very helpful while going through this | 9 | I found the following pages very helpful while going through this process: |
| 10 | process: | ||
| 11 | 10 | ||
| 12 | - [[https://ubuntu.com/tutorials/setup-zfs-storage-pool][Setup a ZFS | 11 | - [[https://ubuntu.com/tutorials/setup-zfs-storage-pool][Setup a ZFS storage pool]] |
| 13 | storage pool]] | ||
| 14 | - [[https://wiki.ubuntu.com/Kernel/Reference/ZFS][Kernel/Reference/ZFS]] | 12 | - [[https://wiki.ubuntu.com/Kernel/Reference/ZFS][Kernel/Reference/ZFS]] |
| 15 | - [[https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/][ZFS for | 13 | - [[https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/][ZFS for Dummies]] |
| 16 | Dummies]] | ||
| 17 | 14 | ||
| 18 | * Installation | 15 | * Installation |
| 19 | 16 | ||
| @@ -23,8 +20,7 @@ To start, I installed the ZFS package with the following command: | |||
| 23 | sudo apt install zfsutils-linux | 20 | sudo apt install zfsutils-linux |
| 24 | #+end_src | 21 | #+end_src |
| 25 | 22 | ||
| 26 | Once installed, you can check the version to see if it installed | 23 | Once installed, you can check the version to see if it installed correctly. |
| 27 | correctly. | ||
| 28 | 24 | ||
| 29 | #+begin_src sh | 25 | #+begin_src sh |
| 30 | > zsf --version | 26 | > zsf --version |
| @@ -37,9 +33,9 @@ zfs-kmod-2.1.5-1ubuntu6~22.04.1 | |||
| 37 | 33 | ||
| 38 | Now that ZFS is installed, we can create and configure the pool. | 34 | Now that ZFS is installed, we can create and configure the pool. |
| 39 | 35 | ||
| 40 | You have various options for configuring ZFS pools that all come | 36 | You have various options for configuring ZFS pools that all come different pros |
| 41 | different pros and cons. I suggest visiting the links at the top of this | 37 | and cons. I suggest visiting the links at the top of this post or searching |
| 42 | post or searching online for the best configuration for your use-case. | 38 | online for the best configuration for your use-case. |
| 43 | 39 | ||
| 44 | - Striped VDEVs (Raid0) | 40 | - Striped VDEVs (Raid0) |
| 45 | - Mirrored VDEVs (Raid1) | 41 | - Mirrored VDEVs (Raid1) |
| @@ -49,20 +45,20 @@ post or searching online for the best configuration for your use-case. | |||
| 49 | - RAIDz3 | 45 | - RAIDz3 |
| 50 | - Nested RAIDz (Raid50, Raid60) | 46 | - Nested RAIDz (Raid50, Raid60) |
| 51 | 47 | ||
| 52 | I will be using Raid10 in this guide. However, the majority of the steps | 48 | I will be using Raid10 in this guide. However, the majority of the steps are the |
| 53 | are the same regardless of your chosen pool configuration. | 49 | same regardless of your chosen pool configuration. |
| 54 | 50 | ||
| 55 | ** Creating the Pool | 51 | ** Creating the Pool |
| 56 | 52 | ||
| 57 | To start, let's list the disks available to use. You can use =fdisk= | 53 | To start, let's list the disks available to use. You can use =fdisk= command to |
| 58 | command to see all available disks. | 54 | see all available disks. |
| 59 | 55 | ||
| 60 | #+begin_src sh | 56 | #+begin_src sh |
| 61 | sudo fdisk -l | 57 | sudo fdisk -l |
| 62 | #+end_src | 58 | #+end_src |
| 63 | 59 | ||
| 64 | Or, if you currently have them mounted, you can use the =df= command to | 60 | Or, if you currently have them mounted, you can use the =df= command to view |
| 65 | view your disks. | 61 | your disks. |
| 66 | 62 | ||
| 67 | #+begin_src sh | 63 | #+begin_src sh |
| 68 | > sudo df -h | 64 | > sudo df -h |
| @@ -77,17 +73,16 @@ Filesystem Size Used Avail Use% Mounted on | |||
| 77 | /dev/sdf1 7.3T 28K 6.9T 1% /mnt/red-04 | 73 | /dev/sdf1 7.3T 28K 6.9T 1% /mnt/red-04 |
| 78 | #+end_src | 74 | #+end_src |
| 79 | 75 | ||
| 80 | If you're going to use mounted disks, make sure to umount them before | 76 | If you're going to use mounted disks, make sure to umount them before creating |
| 81 | creating the pool. | 77 | the pool. |
| 82 | 78 | ||
| 83 | #+begin_src sh | 79 | #+begin_src sh |
| 84 | sudo umount /dev/sda1 | 80 | sudo umount /dev/sda1 |
| 85 | sudo umount /dev/sdb1 | 81 | sudo umount /dev/sdb1 |
| 86 | #+end_src | 82 | #+end_src |
| 87 | 83 | ||
| 88 | Now that I've identified the disks I want to use and have them | 84 | Now that I've identified the disks I want to use and have them unmounted, let's |
| 89 | unmounted, let's create the pool. For this example, I will call it | 85 | create the pool. For this example, I will call it =tank=. |
| 90 | =tank=. | ||
| 91 | 86 | ||
| 92 | #+begin_src sh | 87 | #+begin_src sh |
| 93 | sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb | 88 | sudo zpool create -f -m /mnt/pool tank mirror /dev/sda /dev/sdb |
| @@ -119,8 +114,8 @@ config: | |||
| 119 | errors: No known data errors | 114 | errors: No known data errors |
| 120 | #+end_src | 115 | #+end_src |
| 121 | 116 | ||
| 122 | We can also look at the mounted filesystem to see where the pool is | 117 | We can also look at the mounted filesystem to see where the pool is mounted and |
| 123 | mounted and some quick stats. | 118 | some quick stats. |
| 124 | 119 | ||
| 125 | #+begin_src sh | 120 | #+begin_src sh |
| 126 | > df -h | 121 | > df -h |
| @@ -132,28 +127,25 @@ tank 7.2T 128K 7.2T 1% /tank | |||
| 132 | 127 | ||
| 133 | ** Expanding the Pool | 128 | ** Expanding the Pool |
| 134 | 129 | ||
| 135 | If you want to expand this pool, you will need to add a new VDEV to the | 130 | If you want to expand this pool, you will need to add a new VDEV to the pool. |
| 136 | pool. Since I am using 2 disks per VDEV, I will need to add a new 2-disk | 131 | Since I am using 2 disks per VDEV, I will need to add a new 2-disk VDEV to the |
| 137 | VDEV to the existing =tank= pool. | 132 | existing =tank= pool. |
| 138 | 133 | ||
| 139 | #+begin_src sh | 134 | #+begin_src sh |
| 140 | sudo zpool add tank mirror /dev/sdX /dev/sdY | 135 | sudo zpool add tank mirror /dev/sdX /dev/sdY |
| 141 | #+end_src | 136 | #+end_src |
| 142 | 137 | ||
| 143 | If you're adding disks of different sizes, you'll need to use the =-f= | 138 | If you're adding disks of different sizes, you'll need to use the =-f= flag. |
| 144 | flag. Keep in mind that the max size will be limited to the smallest | 139 | Keep in mind that the max size will be limited to the smallest disk added. |
| 145 | disk added. | ||
| 146 | 140 | ||
| 147 | #+begin_src sh | 141 | #+begin_src sh |
| 148 | sudo zpool add -f tank mirror /dev/sdX /dev/sdY | 142 | sudo zpool add -f tank mirror /dev/sdX /dev/sdY |
| 149 | #+end_src | 143 | #+end_src |
| 150 | 144 | ||
| 151 | I added two 8TB hard drives and this process took around 10 seconds to | 145 | I added two 8TB hard drives and this process took around 10 seconds to complete. |
| 152 | complete. | ||
| 153 | 146 | ||
| 154 | When viewing the pool again, you can see that the pool has now doubled | 147 | When viewing the pool again, you can see that the pool has now doubled in size. |
| 155 | in size. We have 14.3 TB useable space and the same space used for | 148 | We have 14.3 TB useable space and the same space used for mirroring. |
| 156 | mirroring. | ||
| 157 | 149 | ||
| 158 | #+begin_src sh | 150 | #+begin_src sh |
| 159 | > zfs list | 151 | > zfs list |
| @@ -166,8 +158,8 @@ tank/media 96K 14.3T 96K /tank/media | |||
| 166 | 158 | ||
| 167 | *** Converting Disks | 159 | *** Converting Disks |
| 168 | 160 | ||
| 169 | Some disks, such as NTFS-formatted drives, will need to be partitioned | 161 | Some disks, such as NTFS-formatted drives, will need to be partitioned and |
| 170 | and formatted prior to being added to the pool. | 162 | formatted prior to being added to the pool. |
| 171 | 163 | ||
| 172 | Start by identifying the disks you want to format and add to the pool. | 164 | Start by identifying the disks you want to format and add to the pool. |
| 173 | 165 | ||
| @@ -178,8 +170,8 @@ sudo fdisk -l | grep /dev | |||
| 178 | I am going to format my =/dev/sdc= and =/dev/sdd= disks with the =fdisk= | 170 | I am going to format my =/dev/sdc= and =/dev/sdd= disks with the =fdisk= |
| 179 | command. | 171 | command. |
| 180 | 172 | ||
| 181 | See below for instructions on how to use =fdisk=. Here's what I did to | 173 | See below for instructions on how to use =fdisk=. Here's what I did to create |
| 182 | create basic Linux formatted disks: | 174 | basic Linux formatted disks: |
| 183 | 175 | ||
| 184 | - =g= : Create GPT partition table | 176 | - =g= : Create GPT partition table |
| 185 | - =n= : Create a new partition, hit Enter for all default options | 177 | - =n= : Create a new partition, hit Enter for all default options |
| @@ -191,13 +183,12 @@ I repeated this process for both disks. | |||
| 191 | #+begin_src sh | 183 | #+begin_src sh |
| 192 | > sudo fdisk /dev/sdc | 184 | > sudo fdisk /dev/sdc |
| 193 | 185 | ||
| 194 | Welcome to fdisk (util-linux 2.37.2). | 186 | Welcome to fdisk (util-linux 2.37.2). Changes will remain in memory only, until |
| 195 | Changes will remain in memory only, until you decide to write them. | 187 | you decide to write them. Be careful before using the write command. |
| 196 | Be careful before using the write command. | ||
| 197 | 188 | ||
| 198 | This disk is currently in use - repartitioning is probably a bad idea. | 189 | This disk is currently in use - repartitioning is probably a bad idea. It's |
| 199 | It's recommended to umount all file systems, and swapoff all swap | 190 | recommended to umount all file systems, and swapoff all swap partitions on this |
| 200 | partitions on this disk. | 191 | disk. |
| 201 | 192 | ||
| 202 | 193 | ||
| 203 | Command (m for help): m | 194 | Command (m for help): m |
| @@ -243,9 +234,9 @@ sudo zpool add tank mirror /dev/sdc /dev/sdd | |||
| 243 | #+end_src | 234 | #+end_src |
| 244 | 235 | ||
| 245 | When we list the pool again, we can see that our size is now updated to | 236 | When we list the pool again, we can see that our size is now updated to |
| 246 | approximately 22TB. This represents my hard drives totalling 45.6TB when | 237 | approximately 22TB. This represents my hard drives totalling 45.6TB when shown |
| 247 | shown with =fdisk -l=, with a Raid10 configuration using 22TB for | 238 | with =fdisk -l=, with a Raid10 configuration using 22TB for mirroring and 22TB |
| 248 | mirroring and 22TB of useable space. | 239 | of useable space. |
| 249 | 240 | ||
| 250 | #+begin_src sh | 241 | #+begin_src sh |
| 251 | > zfs list | 242 | > zfs list |
| @@ -258,17 +249,15 @@ tank/media 145GT 21.7T 96K /tank/media | |||
| 258 | 249 | ||
| 259 | ** Creating Datasets | 250 | ** Creating Datasets |
| 260 | 251 | ||
| 261 | According to | 252 | According to [[https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html][ZFS Terminology]], a =dataset= can refer to “clones, file systems, |
| 262 | [[https://docs.oracle.com/cd/E18752_01/html/819-5461/ftyue.html][ZFS | ||
| 263 | Terminology]], a =dataset= can refer to “clones, file systems, | ||
| 264 | snapshots, and volumes. | 253 | snapshots, and volumes. |
| 265 | 254 | ||
| 266 | For this guide, I will use the =dataset= term to refer to file systems | 255 | For this guide, I will use the =dataset= term to refer to file systems created |
| 267 | created under a pool. | 256 | under a pool. |
| 268 | 257 | ||
| 269 | Within my =tank= pool, I am going to create some datasets to help | 258 | Within my =tank= pool, I am going to create some datasets to help organize my |
| 270 | organize my files. This will give me location to store data rather than | 259 | files. This will give me location to store data rather than simply dumping |
| 271 | simply dumping everything at the =/tank/= location. | 260 | everything at the =/tank/= location. |
| 272 | 261 | ||
| 273 | #+begin_src sh | 262 | #+begin_src sh |
| 274 | sudo zfs create tank/cloud | 263 | sudo zfs create tank/cloud |
| @@ -288,9 +277,9 @@ tank/media 96K 7.14T 96K /tank/media | |||
| 288 | 277 | ||
| 289 | ** Creating Snapshots | 278 | ** Creating Snapshots |
| 290 | 279 | ||
| 291 | Next, let's create our first snapshot. We can do this by calling the | 280 | Next, let's create our first snapshot. We can do this by calling the =snapshot= |
| 292 | =snapshot= command and give it an output name. I will be throwing the | 281 | command and give it an output name. I will be throwing the current date and time |
| 293 | current date and time into my example. | 282 | into my example. |
| 294 | 283 | ||
| 295 | #+begin_src sh | 284 | #+begin_src sh |
| 296 | sudo zfs snapshot tank@$(date '+%Y-%m-%d_%H-%M') | 285 | sudo zfs snapshot tank@$(date '+%Y-%m-%d_%H-%M') |
| @@ -321,13 +310,10 @@ no datasets available | |||
| 321 | 310 | ||
| 322 | * My Thoughts on ZFS So Far | 311 | * My Thoughts on ZFS So Far |
| 323 | 312 | ||
| 324 | - I sacrificed 25TB to be able to mirror my data, but I feel more | 313 | - I sacrificed 25TB to be able to mirror my data, but I feel more comfortable |
| 325 | comfortable with the potential to save my data by quickly replacing a | 314 | with the potential to save my data by quickly replacing a disk if I need to. |
| 326 | disk if I need to. | ||
| 327 | - The set-up was surprisingly easy and fast. | 315 | - The set-up was surprisingly easy and fast. |
| 328 | - Disk I/O is fast as well. I was worried that the data transfer speeds | 316 | - Disk I/O is fast as well. I was worried that the data transfer speeds would be |
| 329 | would be slower due to the RAID configuration. | 317 | slower due to the RAID configuration. |
| 330 | - Media streaming and transcoding has seen no noticeable drop in | 318 | - Media streaming and transcoding has seen no noticeable drop in performance. |
| 331 | performance. | 319 | - My only limitation really is the number of HDD bays in my server HDD cage. |
| 332 | - My only limitation really is the number of HDD bays in my server HDD | ||
| 333 | cage. | ||
content/blog/2024-02-13-ubuntu-emergency-mode.org +21 −22
| @@ -5,12 +5,12 @@ | |||
| 5 | 5 | ||
| 6 | * The Problem | 6 | * The Problem |
| 7 | 7 | ||
| 8 | I recently [[../zfs/][migrated my hard drives to a ZFS pool]] and found | 8 | I recently [[../zfs/][migrated my hard drives to a ZFS pool]] and found myself stuck in |
| 9 | myself stuck in Ubuntu's emergency mode after the first reboot I | 9 | Ubuntu's emergency mode after the first reboot I performed after creating the |
| 10 | performed after creating the ZFS pool. | 10 | ZFS pool. |
| 11 | 11 | ||
| 12 | My server was stuck in the boot process and showed the following error | 12 | My server was stuck in the boot process and showed the following error on the |
| 13 | on the screen: | 13 | screen: |
| 14 | 14 | ||
| 15 | #+begin_src txt | 15 | #+begin_src txt |
| 16 | You are in emergency mode. | 16 | You are in emergency mode. |
| @@ -19,34 +19,33 @@ After logging in, type "journalctl -xb" to view system logs, | |||
| 19 | or ^D to try again to boot into default mode". | 19 | or ^D to try again to boot into default mode". |
| 20 | #+end_src | 20 | #+end_src |
| 21 | 21 | ||
| 22 | After rebooting the server and watching the logs scroll on a monitor, I | 22 | After rebooting the server and watching the logs scroll on a monitor, I noticed |
| 23 | noticed the root cause was related to a very long search for certain | 23 | the root cause was related to a very long search for certain drives. I kept |
| 24 | drives. I kept seeing errors like this: | 24 | seeing errors like this: |
| 25 | 25 | ||
| 26 | #+begin_src txt | 26 | #+begin_src txt |
| 27 | [ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid] | 27 | [ TIME ] Timed out waiting of device dev-disk-by/[disk-uuid] |
| 28 | #+end_src | 28 | #+end_src |
| 29 | 29 | ||
| 30 | I realized that I had not removed the =/etc/fstab= references that asked | 30 | I realized that I had not removed the =/etc/fstab= references that asked Ubuntu |
| 31 | Ubuntu to mount two disks on boot, but I had recently changed those | 31 | to mount two disks on boot, but I had recently changed those disks to be part of |
| 32 | disks to be part of my ZFS pool instead. Therefore, Ubuntu was trying to | 32 | my ZFS pool instead. Therefore, Ubuntu was trying to identify and mount a disk |
| 33 | identify and mount a disk that was not available. | 33 | that was not available. |
| 34 | 34 | ||
| 35 | Now that we have an idea of the issue, let's move to solution. | 35 | Now that we have an idea of the issue, let's move to solution. |
| 36 | 36 | ||
| 37 | * The Solution | 37 | * The Solution |
| 38 | 38 | ||
| 39 | In order to fix the issue, I waited until I was allowed to type the root | 39 | In order to fix the issue, I waited until I was allowed to type the root user's |
| 40 | user's password, and then I executed the following command: | 40 | password, and then I executed the following command: |
| 41 | 41 | ||
| 42 | #+begin_src sh | 42 | #+begin_src sh |
| 43 | nano /etc/fstab | 43 | nano /etc/fstab |
| 44 | #+end_src | 44 | #+end_src |
| 45 | 45 | ||
| 46 | Within the =fstab= file, I needed to comment/remove the following lines | 46 | Within the =fstab= file, I needed to comment/remove the following lines at the |
| 47 | at the bottom of the file. You can comment-out a line by prepending a | 47 | bottom of the file. You can comment-out a line by prepending a =#= symbol at the |
| 48 | =#= symbol at the beginning of the line. You can also delete the line | 48 | beginning of the line. You can also delete the line entirely. |
| 49 | entirely. | ||
| 50 | 49 | ||
| 51 | #+begin_src conf | 50 | #+begin_src conf |
| 52 | # What it looked like when running into the issue: | 51 | # What it looked like when running into the issue: |
| @@ -58,8 +57,8 @@ UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0 | |||
| 58 | # UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0 | 57 | # UUID=E69867E59867B32B /mnt/white-02 ntfs-3g uid=1000,gid=1000 0 0 |
| 59 | #+end_src | 58 | #+end_src |
| 60 | 59 | ||
| 61 | Once removing the lines above from the =/etc/fstab= file, save and exit | 60 | Once removing the lines above from the =/etc/fstab= file, save and exit the file |
| 62 | the file by hitting the =Ctrl= + =x= key combo. | 61 | by hitting the =Ctrl= + =x= key combo. |
| 63 | 62 | ||
| 64 | You can now hit =Ctrl= + =D= to continue, or reboot: | 63 | You can now hit =Ctrl= + =D= to continue, or reboot: |
| 65 | 64 | ||
| @@ -67,5 +66,5 @@ You can now hit =Ctrl= + =D= to continue, or reboot: | |||
| 67 | systemctl reboot | 66 | systemctl reboot |
| 68 | #+end_src | 67 | #+end_src |
| 69 | 68 | ||
| 70 | Once rebooted, I was able to watch the machine boot properly and launch | 69 | Once rebooted, I was able to watch the machine boot properly and launch to the |
| 71 | to the TTY login screen without errors! | 70 | TTY login screen without errors! |
content/blog/2024-02-21-self-hosting-otter-wiki.org +17 −20
| @@ -5,14 +5,14 @@ | |||
| 5 | 5 | ||
| 6 | * An Otter Wiki | 6 | * An Otter Wiki |
| 7 | 7 | ||
| 8 | [[https://otterwiki.com/][An Otter Wiki]] is an easy to use wiki | 8 | [[https://otterwiki.com/][An Otter Wiki]] is an easy to use wiki software that takes almost no effort to set |
| 9 | software that takes almost no effort to set up and maintain. | 9 | up and maintain. |
| 10 | 10 | ||
| 11 | * Installation | 11 | * Installation |
| 12 | 12 | ||
| 13 | To install An Otter Wiki, I'm going to use Docker Compose to create the | 13 | To install An Otter Wiki, I'm going to use Docker Compose to create the |
| 14 | container and then use Nginx as a reverse proxy to allow external access | 14 | container and then use Nginx as a reverse proxy to allow external access via a |
| 15 | via a subdomain I own. | 15 | subdomain I own. |
| 16 | 16 | ||
| 17 | ** Docker Compose | 17 | ** Docker Compose |
| 18 | 18 | ||
| @@ -22,16 +22,14 @@ Start by creating a directory for the container's files. | |||
| 22 | mkdir ~/otterwiki | 22 | mkdir ~/otterwiki |
| 23 | #+end_src | 23 | #+end_src |
| 24 | 24 | ||
| 25 | Next, create the =docker-compose.yml= file to define the container's | 25 | Next, create the =docker-compose.yml= file to define the container's parameters. |
| 26 | parameters. | ||
| 27 | 26 | ||
| 28 | #+begin_src sh | 27 | #+begin_src sh |
| 29 | nano ~/otterwiki/docker-compose.yml | 28 | nano ~/otterwiki/docker-compose.yml |
| 30 | #+end_src | 29 | #+end_src |
| 31 | 30 | ||
| 32 | Within the file, paste the following content. You can read the project's | 31 | Within the file, paste the following content. You can read the project's |
| 33 | documentation if you want to further override or customize the | 32 | documentation if you want to further override or customize the container. |
| 34 | container. | ||
| 35 | 33 | ||
| 36 | #+begin_src conf | 34 | #+begin_src conf |
| 37 | version: '3' | 35 | version: '3' |
| @@ -54,22 +52,22 @@ cd ~/otterwiki | |||
| 54 | sudo docker-compose up -d | 52 | sudo docker-compose up -d |
| 55 | #+end_src | 53 | #+end_src |
| 56 | 54 | ||
| 57 | The container is now available at =localhost:8337=. Next, we will use | 55 | The container is now available at =localhost:8337=. Next, we will use Nginx to |
| 58 | Nginx to serve this app externally. | 56 | serve this app externally. |
| 59 | 57 | ||
| 60 | ** Nginx | 58 | ** Nginx |
| 61 | 59 | ||
| 62 | To access the app externally, let's set up a reverse proxy. I'll start | 60 | To access the app externally, let's set up a reverse proxy. I'll start by |
| 63 | by creating the Nginx configuration file for my wiki. | 61 | creating the Nginx configuration file for my wiki. |
| 64 | 62 | ||
| 65 | #+begin_src sh | 63 | #+begin_src sh |
| 66 | sudo nano /etc/nginx/sites-available/wiki | 64 | sudo nano /etc/nginx/sites-available/wiki |
| 67 | #+end_src | 65 | #+end_src |
| 68 | 66 | ||
| 69 | Within the file, I have saved the following content. This assumes you | 67 | Within the file, I have saved the following content. This assumes you already |
| 70 | already have a TLS/SSL cert to use with this subdomain. If not, simply | 68 | have a TLS/SSL cert to use with this subdomain. If not, simply remove the |
| 71 | remove the =ssl_*= variables, remove the =80= server block, and change | 69 | =ssl_*= variables, remove the =80= server block, and change the =443= server |
| 72 | the =443= server block to =80= to serve the app without SSL. | 70 | block to =80= to serve the app without SSL. |
| 73 | 71 | ||
| 74 | #+begin_src conf | 72 | #+begin_src conf |
| 75 | server { | 73 | server { |
| @@ -107,15 +105,14 @@ server { | |||
| 107 | } | 105 | } |
| 108 | #+end_src | 106 | #+end_src |
| 109 | 107 | ||
| 110 | Save and close the configuration file. On Nginx, we need to symlink the | 108 | Save and close the configuration file. On Nginx, we need to symlink the file to |
| 111 | file to enable it. | 109 | enable it. |
| 112 | 110 | ||
| 113 | #+begin_src sh | 111 | #+begin_src sh |
| 114 | sudo ln -s /etc/nginx/sites-available/wiki /etc/nginx/sites-enabled/wiki | 112 | sudo ln -s /etc/nginx/sites-available/wiki /etc/nginx/sites-enabled/wiki |
| 115 | #+end_src | 113 | #+end_src |
| 116 | 114 | ||
| 117 | Once enabled, restart the Nginx server to start serving the app | 115 | Once enabled, restart the Nginx server to start serving the app externally. |
| 118 | externally. | ||
| 119 | 116 | ||
| 120 | #+begin_src sh | 117 | #+begin_src sh |
| 121 | sudo systemctl restart nginx.service | 118 | sudo systemctl restart nginx.service |
content/blog/2024-03-13-doom-emacs.org +92 −113
| @@ -5,9 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | ** Screenshots | 6 | ** Screenshots |
| 7 | 7 | ||
| 8 | These screenshots are showing a project opened with projectile, a | 8 | These screenshots are showing a project opened with projectile, a treemacs side |
| 9 | treemacs side pane open with the project contents, multiple buffers | 9 | pane open with the project contents, multiple buffers tiled next to each other, |
| 10 | tiled next to each other, and the help pane open at the bottomm. | 10 | and the help pane open at the bottomm. |
| 11 | 11 | ||
| 12 | The themes are =doom-homage-white= and =doom-homage-black=. | 12 | The themes are =doom-homage-white= and =doom-homage-black=. |
| 13 | 13 | ||
| @@ -19,44 +19,35 @@ The themes are =doom-homage-white= and =doom-homage-black=. | |||
| 19 | 19 | ||
| 20 | ** Getting Started | 20 | ** Getting Started |
| 21 | 21 | ||
| 22 | I have been switching back and forth between | 22 | I have been switching back and forth between [[https://en.wikipedia.org/wiki/Markdown][markdown]] and [[https://en.wikipedia.org/wiki/Org-mode][org-mode]] recently for |
| 23 | [[https://en.wikipedia.org/wiki/Markdown][markdown]] and | 23 | my personal note taking, wiki, and even this blog. As a result, I have been |
| 24 | [[https://en.wikipedia.org/wiki/Org-mode][org-mode]] recently for my | 24 | stumbling further into the world of Emacs and found myself at a point where I |
| 25 | personal note taking, wiki, and even this blog. As a result, I have been | 25 | now prefer to do most of my basic editing within Emacs. |
| 26 | stumbling further into the world of Emacs and found myself at a point | ||
| 27 | where I now prefer to do most of my basic editing within Emacs. | ||
| 28 | 26 | ||
| 29 | I'll leave the markdown vs. org-mode debate for another post, but I love | 27 | I'll leave the markdown vs. org-mode debate for another post, but I love |
| 30 | org-mode's extensibility and interactive nature within Emacs, but it | 28 | org-mode's extensibility and interactive nature within Emacs, but it becomes |
| 31 | becomes very unwieldy in any other client implementation of org-mode - | 29 | very unwieldy in any other client implementation of org-mode - especially on |
| 32 | especially on iOS. On the flip side, markdown is limited in | 30 | iOS. On the flip side, markdown is limited in functionality and fractured into |
| 33 | functionality and fractured into different standards, but it's simple | 31 | different standards, but it's simple and popular enough that there are a |
| 34 | and popular enough that there are a plethora of great clients to choose | 32 | plethora of great clients to choose from that will get the job done. |
| 35 | from that will get the job done. | ||
| 36 | 33 | ||
| 37 | For now, I want to focus on how I have been using Emacs and some of the | 34 | For now, I want to focus on how I have been using Emacs and some of the things |
| 38 | things that would have helped me learn it faster had I known where to | 35 | that would have helped me learn it faster had I known where to start. |
| 39 | start. | ||
| 40 | 36 | ||
| 41 | *** Installation | 37 | *** Installation |
| 42 | 38 | ||
| 43 | This post focuses on [[https://github.com/doomemacs/doomemacs][Doom | 39 | This post focuses on [[https://github.com/doomemacs/doomemacs][Doom Emacs]], which is an Emacs framework that provides an |
| 44 | Emacs]], which is an Emacs framework that provides an alternative | 40 | alternative experience to the vanilla [[https://www.gnu.org/software/emacs/][GNU Emacs]]. |
| 45 | experience to the vanilla [[https://www.gnu.org/software/emacs/][GNU | ||
| 46 | Emacs]]. | ||
| 47 | 41 | ||
| 48 | The | 42 | The [[https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org][Getting Start Guide]] has an extremely detailed walkthrough of installation |
| 49 | [[https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org][Getting | 43 | for all systems, so please refer to that guide for up-to-date instructions. |
| 50 | Start Guide]] has an extremely detailed walkthrough of installation for | ||
| 51 | all systems, so please refer to that guide for up-to-date instructions. | ||
| 52 | 44 | ||
| 53 | I chose to install on macOS, using the Homebrew option with the | 45 | I chose to install on macOS, using the Homebrew option with the |
| 54 | =railwaycat/emacsmacport= version of Emacs. | 46 | =railwaycat/emacsmacport= version of Emacs. |
| 55 | 47 | ||
| 56 | Once the program is installed, you can run the program by typing =emacs= | 48 | Once the program is installed, you can run the program by typing =emacs= in a |
| 57 | in a terminal. If you installed a version of Emacs that supports both a | 49 | terminal. If you installed a version of Emacs that supports both a GUI and TUI, |
| 58 | GUI and TUI, you will have to run =emacs -nw= to get the TUI instead of | 50 | you will have to run =emacs -nw= to get the TUI instead of the default GUI. |
| 59 | the default GUI. | ||
| 60 | 51 | ||
| 61 | *** Configuration | 52 | *** Configuration |
| 62 | 53 | ||
| @@ -65,13 +56,12 @@ Once installed, you can configure Doom by editing the files within the | |||
| 65 | 56 | ||
| 66 | 1. =config.el= - Personal configuration file | 57 | 1. =config.el= - Personal configuration file |
| 67 | 2. =custom.el= - Custom set variables | 58 | 2. =custom.el= - Custom set variables |
| 68 | 3. =init.el= - Doom modules and load order, must run =doom sync= after | 59 | 3. =init.el= - Doom modules and load order, must run =doom sync= after modifying |
| 69 | modifying | 60 | 4. =packages.el= - Declare packages to install in this file, then run =doom |
| 70 | 4. =packages.el= - Declare packages to install in this file, then run | 61 | sync= to install |
| 71 | =doom sync= to install | ||
| 72 | 62 | ||
| 73 | I only needed a few customizations for my configuration, so I'll list | 63 | I only needed a few customizations for my configuration, so I'll list them |
| 74 | them below. | 64 | below. |
| 75 | 65 | ||
| 76 | #+begin_src lisp | 66 | #+begin_src lisp |
| 77 | ;; ~/.doom.d/config.el | 67 | ;; ~/.doom.d/config.el |
| @@ -145,30 +135,28 @@ them below. | |||
| 145 | (default +bindings +smartparens)) | 135 | (default +bindings +smartparens)) |
| 146 | #+end_src | 136 | #+end_src |
| 147 | 137 | ||
| 148 | If you're editing these files within Doom directly, remember to run | 138 | If you're editing these files within Doom directly, remember to run =SPC h r r= |
| 149 | =SPC h r r= to reload the configuration. Also remember to run | 139 | to reload the configuration. Also remember to run =doom sync= for any changes to |
| 150 | =doom sync= for any changes to the =init.el= or =packages.el= files. | 140 | the =init.el= or =packages.el= files. |
| 151 | 141 | ||
| 152 | ** Basic Functionality | 142 | ** Basic Functionality |
| 153 | 143 | ||
| 154 | I kept a cheat sheet note open at first with all of the basic functions | 144 | I kept a cheat sheet note open at first with all of the basic functions typed |
| 155 | typed out, copied as I went through the tutorial. After a little while, | 145 | out, copied as I went through the tutorial. After a little while, I no longer |
| 156 | I no longer needed it. I highly recommend writing down the most | 146 | needed it. I highly recommend writing down the most applicable shortcuts for |
| 157 | applicable shortcuts for your preferred functionality and refer back to | 147 | your preferred functionality and refer back to it until you've memorized it. |
| 158 | it until you've memorized it. | 148 | |
| 159 | 149 | Memorizing the shortcuts will differ based on the type of Emacs framework being | |
| 160 | Memorizing the shortcuts will differ based on the type of Emacs | 150 | used. Personally, migrating from vanilla Emacs to Doom Emacs simplified |
| 161 | framework being used. Personally, migrating from vanilla Emacs to Doom | 151 | everything by a large factor and instantly enabled me to start working on my |
| 162 | Emacs simplified everything by a large factor and instantly enabled me | 152 | projects, eliminating most of the hurdles I was running into. The vanilla emacs |
| 163 | to start working on my projects, eliminating most of the hurdles I was | 153 | hotkeys became obnoxious and I actually stopped using Emacs entirely for about a |
| 164 | running into. The vanilla emacs hotkeys became obnoxious and I actually | 154 | month before trying Doom. |
| 165 | stopped using Emacs entirely for about a month before trying Doom. | 155 | |
| 166 | 156 | For me, the first logical step is to interact with the local filesystem. To do | |
| 167 | For me, the first logical step is to interact with the local filesystem. | 157 | this, I needed to know how to open directories, open files, save files, discard |
| 168 | To do this, I needed to know how to open directories, open files, save | 158 | changes, close files, and switch between open files. Here are some example |
| 169 | files, discard changes, close files, and switch between open files. Here | 159 | shortcuts I've written down in order to accomplish file-based actions. |
| 170 | are some example shortcuts I've written down in order to accomplish | ||
| 171 | file-based actions. | ||
| 172 | 160 | ||
| 173 | | Doom Hotkey | Emacs Hotkey | Description | | 161 | | Doom Hotkey | Emacs Hotkey | Description | |
| 174 | |-----------------+---------------+----------------------------------------| | 162 | |-----------------+---------------+----------------------------------------| |
| @@ -181,30 +169,28 @@ file-based actions. | |||
| 181 | | =SPC b k= | =C-x k= | Kill current buffer | | 169 | | =SPC b k= | =C-x k= | Kill current buffer | |
| 182 | | =SPC w h/j/k/l= | =C-x o=[fn:2] | Move left/down/up/right to next buffer | | 170 | | =SPC w h/j/k/l= | =C-x o=[fn:2] | Move left/down/up/right to next buffer | |
| 183 | 171 | ||
| 184 | In general, when in Doom, you can press =SPC= and wait a second for the | 172 | In general, when in Doom, you can press =SPC= and wait a second for the help |
| 185 | help pane to appear with all available hotkey options. For example, you | 173 | pane to appear with all available hotkey options. For example, you can press |
| 186 | can press =SPC=, wait for the help pane, and then select a key such as | 174 | =SPC=, wait for the help pane, and then select a key such as =g= to enter the |
| 187 | =g= to enter the git help pane and explore further command options. | 175 | git help pane and explore further command options. |
| 188 | 176 | ||
| 189 | ** Editing | 177 | ** Editing |
| 190 | 178 | ||
| 191 | Next in my process is to dive into editing for any languages I'm | 179 | Next in my process is to dive into editing for any languages I'm currently |
| 192 | currently using. In this post, I will just cover Markdown and Org-Mode | 180 | using. In this post, I will just cover Markdown and Org-Mode but I have also |
| 193 | but I have also been slowly adoping some Python and general web dev | 181 | been slowly adoping some Python and general web dev tools as well. |
| 194 | tools as well. | ||
| 195 | 182 | ||
| 196 | *** Markdown | 183 | *** Markdown |
| 197 | 184 | ||
| 198 | #+caption: Markdown Preview | 185 | #+caption: Markdown Preview |
| 199 | [[https://img.cleberg.net/blog/20240314-doom-emacs/markdown.png]] | 186 | [[https://img.cleberg.net/blog/20240314-doom-emacs/markdown.png]] |
| 200 | 187 | ||
| 201 | Markdown is fairly simple as the syntax is limited, so just make sure | 188 | Markdown is fairly simple as the syntax is limited, so just make sure the |
| 202 | the =~/.doom.d/init.el= includes the =markdown= declaration in the | 189 | =~/.doom.d/init.el= includes the =markdown= declaration in the =:lang= section. |
| 203 | =:lang= section. | ||
| 204 | 190 | ||
| 205 | This package includes the following hotkey menus. The insert and toggle | 191 | This package includes the following hotkey menus. The insert and toggle menu |
| 206 | menu expands further, allowing you to insert various markdown elements | 192 | expands further, allowing you to insert various markdown elements and toggle |
| 207 | and toggle things like link hiding. | 193 | things like link hiding. |
| 208 | 194 | ||
| 209 | | Doom Hotkey | Function | | 195 | | Doom Hotkey | Function | |
| 210 | |------------------------------+--------------------------| | 196 | |------------------------------+--------------------------| |
| @@ -221,14 +207,12 @@ and toggle things like link hiding. | |||
| 221 | #+caption: Org-Mode Preview | 207 | #+caption: Org-Mode Preview |
| 222 | [[https://img.cleberg.net/blog/20240314-doom-emacs/org.png]] | 208 | [[https://img.cleberg.net/blog/20240314-doom-emacs/org.png]] |
| 223 | 209 | ||
| 224 | Similar to the markdown section above, ensure that the | 210 | Similar to the markdown section above, ensure that the =~/.doom.d/init.el= |
| 225 | =~/.doom.d/init.el= includes the =org= declaration in the =:lang= | 211 | includes the =org= declaration in the =:lang= section. |
| 226 | section. | ||
| 227 | 212 | ||
| 228 | There are a few hot keys, but a quick search with =SPC : org= shows that | 213 | There are a few hot keys, but a quick search with =SPC : org= shows that there |
| 229 | there are 865 possible org-related functions you can run. I won't | 214 | are 865 possible org-related functions you can run. I won't possibly be able to |
| 230 | possibly be able to list them all, so I will simply cover a few of the | 215 | list them all, so I will simply cover a few of the basic commands I use myself. |
| 231 | basic commands I use myself. | ||
| 232 | 216 | ||
| 233 | | Doom Hotkey | Function | | 217 | | Doom Hotkey | Function | |
| 234 | |----------------+---------------------------------------| | 218 | |----------------+---------------------------------------| |
| @@ -246,32 +230,28 @@ basic commands I use myself. | |||
| 246 | 230 | ||
| 247 | 1. Org-Publish | 231 | 1. Org-Publish |
| 248 | 232 | ||
| 249 | Org includes a | 233 | Org includes a [[https://orgmode.org/manual/Publishing.html][publishing management system]] by default that allows you to |
| 250 | [[https://orgmode.org/manual/Publishing.html][publishing management | 234 | export org files to Org, iCalendar, HTML, LaTex, Markdown, ODT, and Plain |
| 251 | system]] by default that allows you to export org files to Org, | 235 | Text. Most of these can be exported into another buffer and opened, or simply |
| 252 | iCalendar, HTML, LaTex, Markdown, ODT, and Plain Text. Most of these | 236 | to an external file. |
| 253 | can be exported into another buffer and opened, or simply to an | ||
| 254 | external file. | ||
| 255 | 237 | ||
| 256 | While inside an org file, simply run =SPC m e= or | 238 | While inside an org file, simply run =SPC m e= or =M-x org-export-dispatch= |
| 257 | =M-x org-export-dispatch= to open the export menu. This menu will | 239 | to open the export menu. This menu will show all options and ask you to |
| 258 | show all options and ask you to select an option. If you want to | 240 | select an option. If you want to export to HTML, simply press =h= and then |
| 259 | export to HTML, simply press =h= and then =H= (As HTML buffer), =h= | 241 | =H= (As HTML buffer), =h= (As HTML file), or =o= (As HTML file and open). |
| 260 | (As HTML file), or =o= (As HTML file and open). | ||
| 261 | 242 | ||
| 262 | 2. Projects | 243 | 2. Projects |
| 263 | 244 | ||
| 264 | Some publishing options are easier with a defined project in Emacs. | 245 | Some publishing options are easier with a defined project in Emacs. To create |
| 265 | To create a project within Emacs, I use two methods: | 246 | a project within Emacs, I use two methods: |
| 266 | 247 | ||
| 267 | 1. Add the project via the projectile command =SPC p a=. Does not | 248 | 1. Add the project via the projectile command =SPC p a=. Does not always work |
| 268 | always work for me. | 249 | for me. |
| 269 | 2. Add an empty =.projectile= file in the project root. | 250 | 2. Add an empty =.projectile= file in the project root. |
| 270 | 251 | ||
| 271 | Once a project has been created, you can create custom publishing | 252 | Once a project has been created, you can create custom publishing actions |
| 272 | actions within your =~/.doom.d/config.el= file. For example, here's a | 253 | within your =~/.doom.d/config.el= file. For example, here's a test project I |
| 273 | test project I created to try and convert this blog to org-mode | 254 | created to try and convert this blog to org-mode recently. |
| 274 | recently. | ||
| 275 | 255 | ||
| 276 | #+begin_src lisp | 256 | #+begin_src lisp |
| 277 | ;; org-publish | 257 | ;; org-publish |
| @@ -342,19 +322,18 @@ basic commands I use myself. | |||
| 342 | 322 | ||
| 343 | ** General Thoughts | 323 | ** General Thoughts |
| 344 | 324 | ||
| 345 | I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely | 325 | I have enjoyed Doom Emacs (far more than GNU Emacs) and will likely continue to |
| 346 | continue to use it as my main editor for the time being. Org-Mode is | 326 | use it as my main editor for the time being. Org-Mode is certainly the largest |
| 347 | certainly the largest factor here, as I far prefer it over Markdown due | 327 | factor here, as I far prefer it over Markdown due to its inherent features and |
| 348 | to its inherent features and detailed markup options. However, working | 328 | detailed markup options. However, working with org-mode on iOS has been a pain |
| 349 | with org-mode on iOS has been a pain and I will have to see if there's | 329 | and I will have to see if there's an easier way to resolve those issues or if |
| 350 | an easier way to resolve those issues or if going back to separate | 330 | going back to separate Markdown, Reminders, and Calendar apps is easier to work |
| 351 | Markdown, Reminders, and Calendar apps is easier to work with than an | 331 | with than an all-in-one org solution. |
| 352 | all-in-one org solution. | 332 | |
| 353 | 333 | [fn:1] Doom's evil-window functionality is a bit different from GNU Emacs, but | |
| 354 | [fn:1] Doom's evil-window functionality is a bit different from GNU | 334 | you can always switch to the "other" buffer with =C-x o= or =C-x b= to |
| 355 | Emacs, but you can always switch to the "other" buffer with | 335 | get a list of buffers to select. |
| 356 | =C-x o= or =C-x b= to get a list of buffers to select. | 336 | |
| 357 | 337 | [fn:2] Doom's evil-window functionality is a bit different from GNU Emacs, but | |
| 358 | [fn:2] Doom's evil-window functionality is a bit different from GNU | 338 | you can always switch to the "other" buffer with =C-x o= or =C-x b= to |
| 359 | Emacs, but you can always switch to the "other" buffer with | 339 | get a list of buffers to select. |
| 360 | =C-x o= or =C-x b= to get a list of buffers to select. | ||
content/blog/2024-03-15-self-hosting-ddns-updater.org +41 −52
| @@ -6,25 +6,21 @@ | |||
| 6 | #+caption: DDNS Updater Web View | 6 | #+caption: DDNS Updater Web View |
| 7 | [[https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png]] | 7 | [[https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png]] |
| 8 | 8 | ||
| 9 | [[https://github.com/qdm12/ddns-updater][DDNS Updater]] is a program to | 9 | [[https://github.com/qdm12/ddns-updater][DDNS Updater]] is a program to keep DNS A and/or AAAA records updated for multiple |
| 10 | keep DNS A and/or AAAA records updated for multiple DNS providers. | 10 | DNS providers. |
| 11 | 11 | ||
| 12 | If you've read any of my other posts, you'll notice that I have been | 12 | If you've read any of my other posts, you'll notice that I have been searching |
| 13 | searching for and using a few different DDNS updating solutions for | 13 | for and using a few different DDNS updating solutions for years. You'll also |
| 14 | years. You'll also notice that I love any projects that offer a Docker | 14 | notice that I love any projects that offer a Docker Compose solution. |
| 15 | Compose solution. | ||
| 16 | 15 | ||
| 17 | Luckily, DDNS Upater fits both of these preferences. | 16 | Luckily, DDNS Upater fits both of these preferences. |
| 18 | 17 | ||
| 19 | ** Installation | 18 | ** Installation |
| 20 | 19 | ||
| 21 | To get started, always make sure to review the project's | 20 | To get started, always make sure to review the project's [[https://github.com/qdm12/ddns-updater/blob/master/README.md][README]]. I'll be |
| 22 | [[https://github.com/qdm12/ddns-updater/blob/master/README.md][README]]. | 21 | documenting my steps below, but they may have changed by the time you read this. |
| 23 | I'll be documenting my steps below, but they may have changed by the | ||
| 24 | time you read this. | ||
| 25 | 22 | ||
| 26 | The first step is to set up the directories and files required for the | 23 | The first step is to set up the directories and files required for the project. |
| 27 | project. | ||
| 28 | 24 | ||
| 29 | #+begin_src sh | 25 | #+begin_src sh |
| 30 | mkdir ~/ddns-updater | 26 | mkdir ~/ddns-updater |
| @@ -34,43 +30,36 @@ touch ~/ddns-updater/data/config.json | |||
| 34 | 30 | ||
| 35 | *** Configuration | 31 | *** Configuration |
| 36 | 32 | ||
| 37 | The main configuration you need to update is the =data/config.json= | 33 | The main configuration you need to update is the =data/config.json= file. There |
| 38 | file. There is a large list of supported providers in the README, but | 34 | is a large list of supported providers in the README, but I'm going to use |
| 39 | I'm going to use Cloudflare in this example. | 35 | Cloudflare in this example. |
| 40 | 36 | ||
| 41 | #+begin_src sh | 37 | #+begin_src sh |
| 42 | nano ~/ddns-updater/data/config.json | 38 | nano ~/ddns-updater/data/config.json |
| 43 | #+end_src | 39 | #+end_src |
| 44 | 40 | ||
| 45 | When setting up the configuration for Cloudflare, you'll need the | 41 | When setting up the configuration for Cloudflare, you'll need the following: |
| 46 | following: | ||
| 47 | 42 | ||
| 48 | - Required Parameters | 43 | - Required Parameters |
| 49 | - ="zone_identifier"= is the Zone ID of your site from the domain | 44 | - ="zone_identifier"= is the Zone ID of your site from the domain overview |
| 50 | overview page | 45 | page |
| 51 | - ="host"= is your host and can be ="@"=, a subdomain or the wildcard | 46 | - ="host"= is your host and can be ="@"=, a subdomain or the wildcard ="*"=. |
| 52 | ="*"=. See | 47 | See [[https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949][this issue comment for context]]. |
| 53 | [[https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949][this | 48 | - ="ttl"= integer value for record TTL in seconds (specify 1 for automatic) |
| 54 | issue comment for context]]. | 49 | - One of the following ([[https://developers.cloudflare.com/fundamentals/api/get-started/][how to find API keys]]): |
| 55 | - ="ttl"= integer value for record TTL in seconds (specify 1 for | ||
| 56 | automatic) | ||
| 57 | - One of the following | ||
| 58 | ([[https://developers.cloudflare.com/fundamentals/api/get-started/][how | ||
| 59 | to find API keys]]): | ||
| 60 | - Email ="email"= and Global API Key ="key"= | 50 | - Email ="email"= and Global API Key ="key"= |
| 61 | - User service key ="user_service_key"= | 51 | - User service key ="user_service_key"= |
| 62 | - API Token ="token"=, configured with DNS edit permissions for your | 52 | - API Token ="token"=, configured with DNS edit permissions for your DNS |
| 63 | DNS name's zone | 53 | name's zone |
| 64 | - Optional Parameters | 54 | - Optional Parameters |
| 65 | - ="proxied"= can be set to =true= to use the proxy services of | 55 | - ="proxied"= can be set to =true= to use the proxy services of Cloudflare |
| 66 | Cloudflare | 56 | - ="ip_version"= can be =ipv4= (A records), or =ipv6= (AAAA records) or =ipv4 |
| 67 | - ="ip_version"= can be =ipv4= (A records), or =ipv6= (AAAA records) | 57 | or ipv6= (update one of the two, depending on the public ip found). It |
| 68 | or =ipv4 or ipv6= (update one of the two, depending on the public | 58 | defaults to =ipv4 or ipv6=. |
| 69 | ip found). It defaults to =ipv4 or ipv6=. | 59 | - ="ipv6_suffix"= is the IPv6 interface identifier suffix to use. It can be |
| 70 | - ="ipv6_suffix"= is the IPv6 interface identifier suffix to use. It | 60 | for example =0:0:0:0:72ad:8fbb:a54e:bedd/64=. If left empty, it defaults to |
| 71 | can be for example =0:0:0:0:72ad:8fbb:a54e:bedd/64=. If left empty, | 61 | no suffix and the raw public IPv6 address obtained is used in the record |
| 72 | it defaults to no suffix and the raw public IPv6 address obtained is | 62 | updating. |
| 73 | used in the record updating. | ||
| 74 | 63 | ||
| 75 | #+begin_src conf | 64 | #+begin_src conf |
| 76 | { | 65 | { |
| @@ -90,8 +79,8 @@ following: | |||
| 90 | } | 79 | } |
| 91 | #+end_src | 80 | #+end_src |
| 92 | 81 | ||
| 93 | Once you have configured the provider of your choice, correct the file | 82 | Once you have configured the provider of your choice, correct the file and |
| 94 | and directory permissions and ownership. | 83 | directory permissions and ownership. |
| 95 | 84 | ||
| 96 | #+begin_src sh | 85 | #+begin_src sh |
| 97 | cd ~/ddns_updater | 86 | cd ~/ddns_updater |
| @@ -105,8 +94,8 @@ chmod 400 data/config.json | |||
| 105 | 94 | ||
| 106 | *** Docker Compose | 95 | *** Docker Compose |
| 107 | 96 | ||
| 108 | After creating the project structure, let's create the | 97 | After creating the project structure, let's create the =docker-compose.yml= |
| 109 | =docker-compose.yml= file. | 98 | file. |
| 110 | 99 | ||
| 111 | #+begin_src sh | 100 | #+begin_src sh |
| 112 | nano ~/ddns_-pdater/docker-compose.yml | 101 | nano ~/ddns_-pdater/docker-compose.yml |
| @@ -150,22 +139,22 @@ services: | |||
| 150 | restart: always | 139 | restart: always |
| 151 | #+end_src | 140 | #+end_src |
| 152 | 141 | ||
| 153 | After configuring your preferences in the =docker-compose.yml=, launch | 142 | After configuring your preferences in the =docker-compose.yml=, launch the |
| 154 | the container. | 143 | container. |
| 155 | 144 | ||
| 156 | #+begin_src sh | 145 | #+begin_src sh |
| 157 | cd ~/ddns-updater | 146 | cd ~/ddns-updater |
| 158 | sudo docker-compose up -d | 147 | sudo docker-compose up -d |
| 159 | #+end_src | 148 | #+end_src |
| 160 | 149 | ||
| 161 | If you've launched this on your local machine, you can launch | 150 | If you've launched this on your local machine, you can launch =localhost:8097= |
| 162 | =localhost:8097= in your browser to see the results. | 151 | in your browser to see the results. |
| 163 | 152 | ||
| 164 | *** Nginx Reverse Proxy | 153 | *** Nginx Reverse Proxy |
| 165 | 154 | ||
| 166 | If you launched this service on a server, other machine, or just want to | 155 | If you launched this service on a server, other machine, or just want to access |
| 167 | access it remotely via a domain name, you can use Nginx as a reverse | 156 | it remotely via a domain name, you can use Nginx as a reverse proxy to expose |
| 168 | proxy to expose the service publicly. | 157 | the service publicly. |
| 169 | 158 | ||
| 170 | Start by creating the Nginx configuration file. | 159 | Start by creating the Nginx configuration file. |
| 171 | 160 | ||
| @@ -193,8 +182,8 @@ server { | |||
| 193 | } | 182 | } |
| 194 | #+end_src | 183 | #+end_src |
| 195 | 184 | ||
| 196 | Here's a full example that uses my Authelia authentication service to | 185 | Here's a full example that uses my Authelia authentication service to require |
| 197 | require authentication before someone can access the web page. | 186 | authentication before someone can access the web page. |
| 198 | 187 | ||
| 199 | #+begin_src conf | 188 | #+begin_src conf |
| 200 | server { | 189 | server { |
content/blog/2024-03-29-org-blog.org +56 −67
| @@ -3,48 +3,41 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: org-blog | 4 | #+slug: org-blog |
| 5 | 5 | ||
| 6 | First and foremost, apologies to those who subscribe via RSS as I know | 6 | First and foremost, apologies to those who subscribe via RSS as I know that my |
| 7 | that my feed duplicated itself when I moved this blog over to org-mode | 7 | feed duplicated itself when I moved this blog over to org-mode last night. |
| 8 | last night. | ||
| 9 | 8 | ||
| 10 | This post focuses specifically on the configuration and tools I use to | 9 | This post focuses specifically on the configuration and tools I use to blog from |
| 11 | blog from Emacs with Org-Mode and does not focus on Emacs or Org-Mode | 10 | Emacs with Org-Mode and does not focus on Emacs or Org-Mode themselves. Refer to |
| 12 | themselves. Refer to the post I wrote about | 11 | the post I wrote about [[https://cleberg.net/blog/doom-emacs-org-mode.html][Doom Emacs & Org-Mode]] for more information about my base |
| 13 | [[https://cleberg.net/blog/doom-emacs-org-mode.html][Doom Emacs & Org-Mode]] for | 12 | Emacs configuration. |
| 14 | more information about my base Emacs configuration. | ||
| 15 | 13 | ||
| 16 | * Weblorg | 14 | * Weblorg |
| 17 | 15 | ||
| 18 | The first step in blogging with Org-Mode is to choose a method to | 16 | The first step in blogging with Org-Mode is to choose a method to convert the |
| 19 | convert the source files to HTML and publish them. The Worg site | 17 | source files to HTML and publish them. The Worg site maintains a nice list of |
| 20 | maintains a nice list of | 18 | [[https://orgmode.org/worg/org-blog-wiki.html][Blogs and Wikis with Org]], but the tools are inevitably different and |
| 21 | [[https://orgmode.org/worg/org-blog-wiki.html][Blogs and Wikis with | 19 | opinionated, so you'll need to find what works for you. |
| 22 | Org]], but the tools are inevitably different and opinionated, so you'll | 20 | |
| 23 | need to find what works for you. | 21 | I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and the |
| 24 | 22 | native org-publish functions before finally settling on Weblorg. For one reason | |
| 25 | I tried using Jekyll, Hugo, ox-hugo, Nikola, Blorg, org-static-blog, and | 23 | or another, the other solutions were a drastic step down from my previous |
| 26 | the native org-publish functions before finally settling on Weblorg. For | 24 | workflow that used [[https://www.getzola.org/][Zola]] with Markdown content. |
| 27 | one reason or another, the other solutions were a drastic step down from | 25 | |
| 28 | my previous workflow that used [[https://www.getzola.org/][Zola]] with | 26 | [[https://github.com/emacs-love/weblorg][Weblorg]] is a static site generator for [[https://orgmode.org/][org-mode]], built for use within [[https://www.gnu.org/software/emacs/][Emacs]]. |
| 29 | Markdown content. | 27 | Since it's written in Emacs Lisp, there's no need to install other languages or |
| 30 | 28 | frameworks to get started. More than that, you can write in any editor you | |
| 31 | [[https://github.com/emacs-love/weblorg][Weblorg]] is a static site | 29 | please and simply invoke the Emacs build process with the =--script= parameter |
| 32 | generator for [[https://orgmode.org/][org-mode]], built for use within | ||
| 33 | [[https://www.gnu.org/software/emacs/][Emacs]]. Since it's written in | ||
| 34 | Emacs Lisp, there's no need to install other languages or frameworks to | ||
| 35 | get started. More than that, you can write in any editor you please and | ||
| 36 | simply invoke the Emacs build process with the =--script= parameter | ||
| 37 | instead of requiring you to blog inside Emacs. | 30 | instead of requiring you to blog inside Emacs. |
| 38 | 31 | ||
| 39 | ** Installation | 32 | ** Installation |
| 40 | 33 | ||
| 41 | The [[https://emacs.love/weblorg/doc/index.html][Getting Started]] page | 34 | The [[https://emacs.love/weblorg/doc/index.html][Getting Started]] page details broad installation requirements. I am using |
| 42 | details broad installation requirements. I am using Doom Emacs on macOS, | 35 | Doom Emacs on macOS, which requires you to add the package to the |
| 43 | which requires you to add the package to the =~/.doom.d/packages.el= | 36 | =~/.doom.d/packages.el= file and configure the =publish.el= file slightly |
| 44 | file and configure the =publish.el= file slightly differently. | 37 | differently. |
| 45 | 38 | ||
| 46 | To start, add the =htmlize= and =weblorg= packages to Doom, sync the | 39 | To start, add the =htmlize= and =weblorg= packages to Doom, sync the changes, |
| 47 | changes, and reload. | 40 | and reload. |
| 48 | 41 | ||
| 49 | #+begin_src sh | 42 | #+begin_src sh |
| 50 | nano ~/.doom.d/packages.el | 43 | nano ~/.doom.d/packages.el |
| @@ -63,18 +56,17 @@ Either re-open Emacs or hit =SPC h r r= to reload the changes. | |||
| 63 | 56 | ||
| 64 | ** Configuration | 57 | ** Configuration |
| 65 | 58 | ||
| 66 | Now that I've installed weblorg, I need to configure the project. I'll | 59 | Now that I've installed weblorg, I need to configure the project. I'll start by |
| 67 | start by navigating to my site's source code and creating a =publish.el= | 60 | navigating to my site's source code and creating a =publish.el= file. |
| 68 | file. | ||
| 69 | 61 | ||
| 70 | #+begin_src sh | 62 | #+begin_src sh |
| 71 | cd ~/Source/cleberg.net && nano publish.el | 63 | cd ~/Source/cleberg.net && nano publish.el |
| 72 | #+end_src | 64 | #+end_src |
| 73 | 65 | ||
| 74 | Since I'm using Doom, Emacs will not automatically load the packages I | 66 | Since I'm using Doom, Emacs will not automatically load the packages I need |
| 75 | need later in the build process. To compensate, my =publish.el= file | 67 | later in the build process. To compensate, my =publish.el= file needs to |
| 76 | needs to explicitly tell Emacs where Doom stores the =htmlize=, | 68 | explicitly tell Emacs where Doom stores the =htmlize=, =weblorg=, and |
| 77 | =weblorg=, and =templatel= packages. | 69 | =templatel= packages. |
| 78 | 70 | ||
| 79 | #+begin_src lisp | 71 | #+begin_src lisp |
| 80 | ;; explicity load packages since I'm using Doom Emacs | 72 | ;; explicity load packages since I'm using Doom Emacs |
| @@ -184,12 +176,10 @@ needs to explicitly tell Emacs where Doom stores the =htmlize=, | |||
| 184 | ** Structure | 176 | ** Structure |
| 185 | 177 | ||
| 186 | The project structure for weblorg is highly customizable and the main | 178 | The project structure for weblorg is highly customizable and the main |
| 187 | restriction is that the =publish.el= file must point to the correct | 179 | restriction is that the =publish.el= file must point to the correct paths. |
| 188 | paths. | ||
| 189 | 180 | ||
| 190 | For my blog, I prefer to keep the blog content out of the top-level | 181 | For my blog, I prefer to keep the blog content out of the top-level directory. |
| 191 | directory. This results in the following structure (shortened for | 182 | This results in the following structure (shortened for brevity): |
| 192 | brevity): | ||
| 193 | 183 | ||
| 194 | #+begin_src txt | 184 | #+begin_src txt |
| 195 | .build/ | 185 | .build/ |
| @@ -217,17 +207,17 @@ build.sh | |||
| 217 | publish.el | 207 | publish.el |
| 218 | #+end_src | 208 | #+end_src |
| 219 | 209 | ||
| 220 | This is simply my preferred structure and you can alter it to fit your | 210 | This is simply my preferred structure and you can alter it to fit your needs. |
| 221 | needs. The key here really is that you can customize at will, as long as | 211 | The key here really is that you can customize at will, as long as the |
| 222 | the =publish.el= file matches. | 212 | =publish.el= file matches. |
| 223 | 213 | ||
| 224 | ** Build & Deploy | 214 | ** Build & Deploy |
| 225 | 215 | ||
| 226 | Once you're content with the status of the project, you're ready to | 216 | Once you're content with the status of the project, you're ready to build and |
| 227 | build and deploy the blog. | 217 | deploy the blog. |
| 228 | 218 | ||
| 229 | My process utilizes a =build.sh= script that combines the steps I take | 219 | My process utilizes a =build.sh= script that combines the steps I take every |
| 230 | every time. | 220 | time. |
| 231 | 221 | ||
| 232 | #+begin_src sh | 222 | #+begin_src sh |
| 233 | touch build.sh && chmod +x build.sh && nano build.sh | 223 | touch build.sh && chmod +x build.sh && nano build.sh |
| @@ -235,16 +225,16 @@ touch build.sh && chmod +x build.sh && nano build.sh | |||
| 235 | 225 | ||
| 236 | Within this script, I do the following: | 226 | Within this script, I do the following: |
| 237 | 227 | ||
| 238 | 1. Remove any files within the =.build= directory that I use to store | 228 | 1. Remove any files within the =.build= directory that I use to store published |
| 239 | published files. | 229 | files. |
| 240 | 2. Set the environment variable to =prod= to ensure the =base_url= | 230 | 2. Set the environment variable to =prod= to ensure the =base_url= matches my |
| 241 | matches my configuration in =publish.el=. | 231 | configuration in =publish.el=. |
| 242 | 3. Build the site with Emacs & =publish.el=. | 232 | 3. Build the site with Emacs & =publish.el=. |
| 243 | 4. Use =scp= to copy files to my site's public directory on my server. | 233 | 4. Use =scp= to copy files to my site's public directory on my server. |
| 244 | 234 | ||
| 245 | #+begin_src sh | 235 | #+begin_src sh |
| 246 | rm -rf .build/* && \ | 236 | rm -rf .build/* && \ |
| 247 | ENV=prod emacs --script publish.el && \ | 237 | ENV=prod emacs--script publish.el && \ |
| 248 | scp -r .build/* ubuntu:/var/www/cleberg.net/ | 238 | scp -r .build/* ubuntu:/var/www/cleberg.net/ |
| 249 | #+end_src | 239 | #+end_src |
| 250 | 240 | ||
| @@ -252,13 +242,12 @@ scp -r .build/* ubuntu:/var/www/cleberg.net/ | |||
| 252 | 242 | ||
| 253 | My only current complaints are: | 243 | My only current complaints are: |
| 254 | 244 | ||
| 255 | 1. Errors messages are not helpful. It takes work to determine what the | 245 | 1. Errors messages are not helpful. It takes work to determine what the error is |
| 256 | error is and where it's coming from. I generally have to sit and | 246 | and where it's coming from. I generally have to sit and watch the build |
| 257 | watch the build process to see the file that weblorg pubslishes right | 247 | process to see the file that weblorg pubslishes right before the error |
| 258 | before the error occurred. | 248 | occurred. |
| 259 | 2. The build process re-builds every single file on each run, which | 249 | 2. The build process re-builds every single file on each run, which takes a long |
| 260 | takes a long time for a blog of my size. See below for the last time | 250 | time for a blog of my size. See below for the last time I measured. |
| 261 | I measured. | ||
| 262 | 251 | ||
| 263 | #+begin_src sh | 252 | #+begin_src sh |
| 264 | > time ./build.sh | 253 | > time ./build.sh |
| @@ -266,5 +255,5 @@ My only current complaints are: | |||
| 266 | ./build.sh 35.46s user 0.59s system 85% cpu 41.965 total | 255 | ./build.sh 35.46s user 0.59s system 85% cpu 41.965 total |
| 267 | #+end_src | 256 | #+end_src |
| 268 | 257 | ||
| 269 | Overall, I have thoroughly enjoyed using weblog and will continue to use | 258 | Overall, I have thoroughly enjoyed using weblog and will continue to use it |
| 270 | it going forward until I find something better. | 259 | going forward until I find something better. |
content/blog/2024-04-06-convert-onenote-to-markdown.org +41 −47
| @@ -3,54 +3,49 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: convert-onenote-to-markdown | 4 | #+slug: convert-onenote-to-markdown |
| 5 | 5 | ||
| 6 | If you're looking to convert your OneNote content to another format, | 6 | If you're looking to convert your OneNote content to another format, such as |
| 7 | such as Markdown or Org-Mode, you're in luck. I use a solution that | 7 | Markdown or Org-Mode, you're in luck. I use a solution that doesn't require |
| 8 | doesn't require other programs, such as Evernote or Notion. Personally, | 8 | other programs, such as Evernote or Notion. Personally, I used this solution on |
| 9 | I used this solution on a managed corporate laptop that doesn't allow | 9 | a managed corporate laptop that doesn't allow installation of other programs |
| 10 | installation of other programs like these. | 10 | like these. |
| 11 | 11 | ||
| 12 | This solution uses OneNote and Pandoc on Windows 10. | 12 | This solution uses OneNote and Pandoc on Windows 10. |
| 13 | 13 | ||
| 14 | * Export OneNote Content to Word | 14 | * Export OneNote Content to Word |
| 15 | 15 | ||
| 16 | To start, export any pages or tabs from OneNote to the Word format | 16 | To start, export any pages or tabs from OneNote to the Word format (=.docx=): |
| 17 | (=.docx=): | ||
| 18 | 17 | ||
| 19 | 1. Open OneNote desktop. | 18 | 1. Open OneNote desktop. |
| 20 | 2. Select =File= and then =Export=. | 19 | 2. Select =File= and then =Export=. |
| 21 | 3. Select the scope of content to export, such as =Tab= or =Page=. | 20 | 3. Select the scope of content to export, such as =Tab= or =Page=. |
| 22 | 4. Name and save the file in an easy to remember location. I recommend | 21 | 4. Name and save the file in an easy to remember location. I recommend your |
| 23 | your Downloads or Desktop folder. | 22 | Downloads or Desktop folder. |
| 24 | 23 | ||
| 25 | See below for a visual walkthrough of the export process. | 24 | See below for a visual walkthrough of the export process. |
| 26 | 25 | ||
| 27 | * Download Pandoc | 26 | * Download Pandoc |
| 28 | 27 | ||
| 29 | Start by downloading Pandoc from their | 28 | Start by downloading Pandoc from their [[https://github.com/jgm/pandoc/releases][GitHub releases]] page. I cannot install |
| 30 | [[https://github.com/jgm/pandoc/releases][GitHub releases]] page. I | 29 | =.msi= files on my corporate laptop, so I downloaded the |
| 31 | cannot install =.msi= files on my corporate laptop, so I downloaded the | 30 | =pandoc-3.1.12.3-windows-x86_64.zip= file, which contains a simple =.exe= file |
| 32 | =pandoc-3.1.12.3-windows-x86_64.zip= file, which contains a simple | 31 | that you do not need to install - you will simply run it from the command line |
| 33 | =.exe= file that you do not need to install - you will simply run it | 32 | below. |
| 34 | from the command line below. | ||
| 35 | 33 | ||
| 36 | Once downloaded, unzip the archive and move the =pandoc.exe= file to the | 34 | Once downloaded, unzip the archive and move the =pandoc.exe= file to the same |
| 37 | same folder where your Word documents were saved above. If you prefer, | 35 | folder where your Word documents were saved above. If you prefer, you can move |
| 38 | you can move this file to an easier location, such as | 36 | this file to an easier location, such as =C:\Users\youruser\Downloads=. |
| 39 | =C:\Users\youruser\Downloads=. | ||
| 40 | 37 | ||
| 41 | * Convert Word to Markdown | 38 | * Convert Word to Markdown |
| 42 | 39 | ||
| 43 | In this example, I will be converting the Word documents to Markdown, | 40 | In this example, I will be converting the Word documents to Markdown, but Pandoc |
| 44 | but Pandoc supports | 41 | supports [[https://github.com/jgm/pandoc?tab=readme-ov-file#the-universal-markup-converter][a ton of different formats for conversion]]. Choose the format you prefer |
| 45 | [[https://github.com/jgm/pandoc?tab=readme-ov-file#the-universal-markup-converter][a | ||
| 46 | ton of different formats for conversion]]. Choose the format you prefer | ||
| 47 | and then modify the following commands as needed. | 42 | and then modify the following commands as needed. |
| 48 | 43 | ||
| 49 | To perform the conversion, open the Command Prompt. If you can't find | 44 | To perform the conversion, open the Command Prompt. If you can't find it, open |
| 50 | it, open the start menu and search for it. | 45 | the start menu and search for it. |
| 51 | 46 | ||
| 52 | Within the command prompt, navigate to the directory where you stored | 47 | Within the command prompt, navigate to the directory where you stored the |
| 53 | the =pandoc.exe= file and the Word documents. | 48 | =pandoc.exe= file and the Word documents. |
| 54 | 49 | ||
| 55 | #+begin_src ps1 | 50 | #+begin_src ps1 |
| 56 | cd "C:\Users\yourusername\Downloads" | 51 | cd "C:\Users\yourusername\Downloads" |
| @@ -63,9 +58,9 @@ command. | |||
| 63 | dir | 58 | dir |
| 64 | #+end_src | 59 | #+end_src |
| 65 | 60 | ||
| 66 | Once you have verified that you have the command prompt open in the | 61 | Once you have verified that you have the command prompt open in the correct |
| 67 | correct directory with the =pandoc.exe= and the Word documents, you can | 62 | directory with the =pandoc.exe= and the Word documents, you can run the |
| 68 | run the following loop to convert all Word documents to Markdown. | 63 | following loop to convert all Word documents to Markdown. |
| 69 | 64 | ||
| 70 | #+begin_src ps1 | 65 | #+begin_src ps1 |
| 71 | for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f.md") | 66 | for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f.md") |
| @@ -73,25 +68,24 @@ for %f in (*.docx) do (pandoc.exe --extract-media=. --wrap=preserve "%f" -o "%f. | |||
| 73 | 68 | ||
| 74 | This loop will perform the following actions: | 69 | This loop will perform the following actions: |
| 75 | 70 | ||
| 76 | 1. Find all documents matching the pattern =*.docx=, which means all | 71 | 1. Find all documents matching the pattern =*.docx=, which means all Word |
| 77 | Word documents ending with that file extension. | 72 | documents ending with that file extension. |
| 78 | 2. Iterate through all files found in step 1. | 73 | 2. Iterate through all files found in step 1. |
| 79 | 3. For each file, perform the pandoc command. | 74 | 3. For each file, perform the pandoc command. |
| 80 | 4. Within the pandoc command, =--extract-media= saves all media found in | 75 | 4. Within the pandoc command, =--extract-media= saves all media found in the |
| 81 | the files to the current folder, with pandoc automatically creating a | 76 | files to the current folder, with pandoc automatically creating a =media= |
| 82 | =media= subfolder to hold all images. | 77 | subfolder to hold all images. |
| 83 | 5. Within the pandoc command, =--wrap=preserve= will attempt to prseerve | 78 | 5. Within the pandoc command, =--wrap=preserve= will attempt to prseerve the |
| 84 | the wrapping from the source document. | 79 | wrapping from the source document. |
| 85 | 6. Within the pandoc command, the final step is to specify the output | 80 | 6. Within the pandoc command, the final step is to specify the output path with |
| 86 | path with =-o=. This option adds the =.md= file extension to | 81 | =-o=. This option adds the =.md= file extension to recognize the output files |
| 87 | recognize the output files as Markdown files. | 82 | as Markdown files. |
| 88 | 83 | ||
| 89 | If you want to export to another format, simply specify the | 84 | If you want to export to another format, simply specify the =-f==/=--from== and |
| 90 | =-f==/=--from== and =-t==/=--to== options. | 85 | =-t==/=--to== options. |
| 91 | 86 | ||
| 92 | For example, you can convert the Word document to org-mode. You can also | 87 | For example, you can convert the Word document to org-mode. You can also convert |
| 93 | convert to one format and subsequently convert to other formats as | 88 | to one format and subsequently convert to other formats as needed. |
| 94 | needed. | ||
| 95 | 89 | ||
| 96 | #+begin_src ps1 | 90 | #+begin_src ps1 |
| 97 | pandoc.exe -f docx -t org file.docx | 91 | pandoc.exe -f docx -t org file.docx |
content/blog/2024-04-08-docker-local-web-server.org +35 −38
| @@ -3,43 +3,42 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: docker-local-web-server | 4 | #+slug: docker-local-web-server |
| 5 | 5 | ||
| 6 | When developing websites locally, I often use a simple Python web server | 6 | When developing websites locally, I often use a simple Python web server to |
| 7 | to observe the changes. | 7 | observe the changes. |
| 8 | 8 | ||
| 9 | #+begin_src sh | 9 | #+begin_src sh |
| 10 | python3 -m http.server | 10 | python3 -m http.server |
| 11 | #+end_src | 11 | #+end_src |
| 12 | 12 | ||
| 13 | However, this approach has its limitations. For example, this approach | 13 | However, this approach has its limitations. For example, this approach does not |
| 14 | does not enable logging or access controls. You also need to customize | 14 | enable logging or access controls. You also need to customize =SimpleHTTPServer= |
| 15 | =SimpleHTTPServer= if you have advanced needs from your web server. | 15 | if you have advanced needs from your web server. |
| 16 | 16 | ||
| 17 | So, I went to find an alternative that is almost as easy and far more | 17 | So, I went to find an alternative that is almost as easy and far more extensible |
| 18 | extensible and found Docker Desktop to be a suitable replacement. | 18 | and found Docker Desktop to be a suitable replacement. |
| 19 | 19 | ||
| 20 | * Docker Desktop | 20 | * Docker Desktop |
| 21 | 21 | ||
| 22 | ** Installation | 22 | ** Installation |
| 23 | 23 | ||
| 24 | [[https://www.docker.com/products/docker-desktop/][Docker Desktop]] is a | 24 | [[https://www.docker.com/products/docker-desktop/][Docker Desktop]] is a desktop GUI for the phenomenal Docker container software. |
| 25 | desktop GUI for the phenomenal Docker container software. This allows | 25 | This allows you to manage containers, images, volumes, environments, and |
| 26 | you to manage containers, images, volumes, environments, and extensions | 26 | extensions via an easy-to-use GUI. |
| 27 | via an easy-to-use GUI. | ||
| 28 | 27 | ||
| 29 | To install, open the link above and click the =Download= button for your | 28 | To install, open the link above and click the =Download= button for your |
| 30 | platform. I'm going through this process on an M2 Macbook, so I | 29 | platform. I'm going through this process on an M2 Macbook, so I downloaded the |
| 31 | downloaded the Mac - Apple Chip version. | 30 | Mac - Apple Chip version. |
| 32 | 31 | ||
| 33 | Open the installer and follow the installation process until the | 32 | Open the installer and follow the installation process until the application |
| 34 | application finishes the installation process. | 33 | finishes the installation process. |
| 35 | 34 | ||
| 36 | #+caption: Docker Desktop on macOS | 35 | #+caption: Docker Desktop on macOS |
| 37 | [[https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png]] | 36 | [[https://img.cleberg.net/blog/20240408-docker-local-web-server/docker-desktop.png]] |
| 38 | 37 | ||
| 39 | ** Creating an Nginx Container | 38 | ** Creating an Nginx Container |
| 40 | 39 | ||
| 41 | I prefer to use the command line to create containers, so the following | 40 | I prefer to use the command line to create containers, so the following commands |
| 42 | commands will be input via the terminal. | 41 | will be input via the terminal. |
| 43 | 42 | ||
| 44 | The following command will create a container, using the =nginx= image: | 43 | The following command will create a container, using the =nginx= image: |
| 45 | 44 | ||
| @@ -61,20 +60,20 @@ You can navigate to [[http://localhost:8000]] to see the resulting page. | |||
| 61 | 60 | ||
| 62 | ** Customizing the Nginx Container | 61 | ** Customizing the Nginx Container |
| 63 | 62 | ||
| 64 | Now that I have a container running the Nginx web server, I need to link | 63 | Now that I have a container running the Nginx web server, I need to link some |
| 65 | some volumes so that I can modify the site configuration and provide the | 64 | volumes so that I can modify the site configuration and provide the web files to |
| 66 | web files to serve. | 65 | serve. |
| 67 | 66 | ||
| 68 | Let's start with the new command, which adds two volumes: | 67 | Let's start with the new command, which adds two volumes: |
| 69 | 68 | ||
| 70 | 1. =<your_content>:/usr/share/nginx/html=: This is the directory where | 69 | 1. =<your_content>:/usr/share/nginx/html=: This is the directory where you will |
| 71 | you will provide the web pages for the server to serve. | 70 | provide the web pages for the server to serve. |
| 72 | 2. =<your_config>:/etc/nginx/conf.d/default.conf=: This is the Nginx | 71 | 2. =<your_config>:/etc/nginx/conf.d/default.conf=: This is the Nginx |
| 73 | configuration file for your site. | 72 | configuration file for your site. |
| 74 | 73 | ||
| 75 | To see the updates, you can delete the previous container in the GUI or | 74 | To see the updates, you can delete the previous container in the GUI or run |
| 76 | run =docker stop web= to stop the container. Once stopped, you can run | 75 | =docker stop web= to stop the container. Once stopped, you can run the new |
| 77 | the new =docker run= command below. | 76 | =docker run= command below. |
| 78 | 77 | ||
| 79 | #+begin_src sh | 78 | #+begin_src sh |
| 80 | docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/share/nginx/html -v ~/Source/cleberg.net/nginx-config.conf:/etc/nginx/conf.d/default.conf nginx | 79 | docker run -it -d -p 8000:80 --name web -v ~/Source/cleberg.net/.build:/usr/share/nginx/html -v ~/Source/cleberg.net/nginx-config.conf:/etc/nginx/conf.d/default.conf nginx |
| @@ -107,16 +106,15 @@ server { | |||
| 107 | 106 | ||
| 108 | * Customizing Deployment Actions | 107 | * Customizing Deployment Actions |
| 109 | 108 | ||
| 110 | I am currently blogging with [[https://emacs.love/weblorg/][weblorg]], | 109 | I am currently blogging with [[https://emacs.love/weblorg/][weblorg]], which uses a custom =publish.el= file to |
| 111 | which uses a custom =publish.el= file to build the static site. Within | 110 | build the static site. Within this file, I have configured my deployment process |
| 112 | this file, I have configured my deployment process to check for the | 111 | to check for the =ENV= variable in thesh and if it's set to =prod=, the script |
| 113 | =ENV= variable in thesh and if it's set to =prod=, the script will set | 112 | will set the base URLs to =https://cleberg.net=. If not, it sets the base URLs |
| 114 | the base URLs to =https://cleberg.net=. If not, it sets the base URLs to | 113 | to =localhost:8000= (which matches the port used in the container above). |
| 115 | =localhost:8000= (which matches the port used in the container above). | ||
| 116 | 114 | ||
| 117 | Therefore, I have modified my =build.sh= script to build with | 115 | Therefore, I have modified my =build.sh= script to build with =localhost= URLs |
| 118 | =localhost= URLs if =ENV= is not set to =prod=. It also prevents the | 116 | if =ENV= is not set to =prod=. It also prevents the build process from sending |
| 119 | build process from sending the built files to the production web server. | 117 | the built files to the production web server. |
| 120 | 118 | ||
| 121 | #+begin_src sh | 119 | #+begin_src sh |
| 122 | #!/bin/bash | 120 | #!/bin/bash |
| @@ -133,7 +131,6 @@ else | |||
| 133 | fi | 131 | fi |
| 134 | #+end_src | 132 | #+end_src |
| 135 | 133 | ||
| 136 | You can modify the container in numerous ways and this approach allows | 134 | You can modify the container in numerous ways and this approach allows you to |
| 137 | you to create complex scenarios for your web development purposes. I | 135 | create complex scenarios for your web development purposes. I highly recommend |
| 138 | highly recommend switching over to a container-based approach for | 136 | switching over to a container-based approach for simple, local web development. |
| 139 | simple, local web development. | ||
content/blog/2024-04-18-mu4e.org +36 −42
| @@ -3,20 +3,18 @@ | |||
| 3 | #+description: | 3 | #+description: |
| 4 | #+slug: mu4e | 4 | #+slug: mu4e |
| 5 | 5 | ||
| 6 | This post was heavily inspired by | 6 | This post was heavily inspired by [[https://macowners.club/posts/email-emacs-mu4e-macos/][Email setup in Emacs with Mu4e on macOS]], but |
| 7 | [[https://macowners.club/posts/email-emacs-mu4e-macos/][Email setup in | 7 | with my own tweaks for a single-account configuration and some Doom-specific |
| 8 | Emacs with Mu4e on macOS]], but with my own tweaks for a single-account | 8 | configurations. |
| 9 | configuration and some Doom-specific configurations. | ||
| 10 | 9 | ||
| 11 | * Overview | 10 | * Overview |
| 12 | 11 | ||
| 13 | [[https://github.com/emacsmirror/mu4e][Mu4e]] is an Emacs-based email | 12 | [[https://github.com/emacsmirror/mu4e][Mu4e]] is an Emacs-based email client based on [[https://www.djcbsoftware.nl/code/mu/][mu]], an indexer that stores email in |
| 14 | client based on [[https://www.djcbsoftware.nl/code/mu/][mu]], an indexer | 13 | the Maildir format. |
| 15 | that stores email in the Maildir format. | ||
| 16 | 14 | ||
| 17 | This blog post covers the installation of Mu4e in Doom Emacs on macOS. | 15 | This blog post covers the installation of Mu4e in Doom Emacs on macOS. This |
| 18 | This guide should be very similar to GNU Emacs and Linux-based systems, | 16 | guide should be very similar to GNU Emacs and Linux-based systems, with a few |
| 19 | with a few tweaks required in the various configuration files. | 17 | tweaks required in the various configuration files. |
| 20 | 18 | ||
| 21 | * Installation | 19 | * Installation |
| 22 | 20 | ||
| @@ -34,21 +32,21 @@ mkdir ~/.maildir/certificates # used to store system root certificates | |||
| 34 | 32 | ||
| 35 | *** Store Email Account Passwords in macOS Keychain | 33 | *** Store Email Account Passwords in macOS Keychain |
| 36 | 34 | ||
| 37 | Next, I will be using the macOS Keychain to store my email account | 35 | Next, I will be using the macOS Keychain to store my email account passwords |
| 38 | passwords using the command below. | 36 | using the command below. |
| 39 | 37 | ||
| 40 | #+begin_src sh | 38 | #+begin_src sh |
| 41 | security add-generic-password -s mu4e-example -a you@example.com -w | 39 | security add-generic-password -s mu4e-example -a you@example.com -w |
| 42 | #+end_src | 40 | #+end_src |
| 43 | 41 | ||
| 44 | This will prompt you to input your password twice to confirm. Keep the | 42 | This will prompt you to input your password twice to confirm. Keep the |
| 45 | =mu4e-example= name in mind, as you will need to reference it later in | 43 | =mu4e-example= name in mind, as you will need to reference it later in the IMAP |
| 46 | the IMAP and SMTP configuration files. | 44 | and SMTP configuration files. |
| 47 | 45 | ||
| 48 | *** Store Root Certificates | 46 | *** Store Root Certificates |
| 49 | 47 | ||
| 50 | In order to use IMAP and SMTP, we need to provide certificates to the | 48 | In order to use IMAP and SMTP, we need to provide certificates to the local |
| 51 | local services. We will use the macOS defaults for this. | 49 | services. We will use the macOS defaults for this. |
| 52 | 50 | ||
| 53 | 1. Open =Keychain Access.app=. | 51 | 1. Open =Keychain Access.app=. |
| 54 | 2. Select =System Roots= in the sidebar. | 52 | 2. Select =System Roots= in the sidebar. |
| @@ -58,8 +56,8 @@ local services. We will use the macOS defaults for this. | |||
| 58 | 56 | ||
| 59 | *** Install Dependencies | 57 | *** Install Dependencies |
| 60 | 58 | ||
| 61 | Install =mbsync= (via =isync=) to fetch emails via IMAP, =mu= to index | 59 | Install =mbsync= (via =isync=) to fetch emails via IMAP, =mu= to index emails, |
| 62 | emails, and =msmtp= to send emails via SMTP. | 60 | and =msmtp= to send emails via SMTP. |
| 63 | 61 | ||
| 64 | #+begin_src sh | 62 | #+begin_src sh |
| 65 | brew install mu isync msmtp | 63 | brew install mu isync msmtp |
| @@ -73,8 +71,8 @@ Within Doom Emacs, we can install Mu4e by enabling the package. | |||
| 73 | nano ~/.doom.d/init.el | 71 | nano ~/.doom.d/init.el |
| 74 | #+end_src | 72 | #+end_src |
| 75 | 73 | ||
| 76 | In this file, uncomment the =mu4e= line within the =:email= section. You | 74 | In this file, uncomment the =mu4e= line within the =:email= section. You can |
| 77 | can also enable the =+org= and =+gmail= options if you prefer. | 75 | also enable the =+org= and =+gmail= options if you prefer. |
| 78 | 76 | ||
| 79 | #+begin_src lisp | 77 | #+begin_src lisp |
| 80 | (doom! :input | 78 | (doom! :input |
| @@ -88,9 +86,9 @@ can also enable the =+org= and =+gmail= options if you prefer. | |||
| 88 | 86 | ||
| 89 | * Configuration | 87 | * Configuration |
| 90 | 88 | ||
| 91 | As an overall suggestion, I create the following configuration files in | 89 | As an overall suggestion, I create the following configuration files in the |
| 92 | the =~/.maildir= directory and using symlinks to their proper locations | 90 | =~/.maildir= directory and using symlinks to their proper locations so that I |
| 93 | so that I can backup and restore these files easily. | 91 | can backup and restore these files easily. |
| 94 | 92 | ||
| 95 | #+begin_src sh | 93 | #+begin_src sh |
| 96 | touch ~/.maildir/.mbsyncrc && \ | 94 | touch ~/.maildir/.mbsyncrc && \ |
| @@ -99,14 +97,13 @@ ln -s /Users/username/.maildir/.mbsyncrc /Users/username/.mbsyncrc && \ | |||
| 99 | ln -s /Users/username/.maildir/.msmtprc /Users/username/.msmtprc | 97 | ln -s /Users/username/.maildir/.msmtprc /Users/username/.msmtprc |
| 100 | #+end_src | 98 | #+end_src |
| 101 | 99 | ||
| 102 | You can also create these files in your home directory and skip the | 100 | You can also create these files in your home directory and skip the symlinking |
| 103 | symlinking process above. | 101 | process above. |
| 104 | 102 | ||
| 105 | ** IMAP | 103 | ** IMAP |
| 106 | 104 | ||
| 107 | Next, let's configure =mbsync= in the file created above. Paste the | 105 | Next, let's configure =mbsync= in the file created above. Paste the following |
| 108 | following information and customize it to match your mail provider's | 106 | information and customize it to match your mail provider's information. |
| 109 | information. | ||
| 110 | 107 | ||
| 111 | #+begin_src sh | 108 | #+begin_src sh |
| 112 | nano ~/.maildir/.mbsyncrc | 109 | nano ~/.maildir/.mbsyncrc |
| @@ -142,9 +139,8 @@ SyncState * | |||
| 142 | 139 | ||
| 143 | ** SMTP | 140 | ** SMTP |
| 144 | 141 | ||
| 145 | Next, let's configured =msmtprc= in the file created above. Paste the | 142 | Next, let's configured =msmtprc= in the file created above. Paste the following |
| 146 | following information and customize it to match your mail provider's | 143 | information and customize it to match your mail provider's information. |
| 147 | information. | ||
| 148 | 144 | ||
| 149 | #+begin_src sh | 145 | #+begin_src sh |
| 150 | nano ~/.maildir/.msmtprc | 146 | nano ~/.maildir/.msmtprc |
| @@ -176,8 +172,8 @@ account default : startmail | |||
| 176 | 172 | ||
| 177 | ** Doom Emacs | 173 | ** Doom Emacs |
| 178 | 174 | ||
| 179 | Finally, we need to configure Doom Emacs to use the proper packages and | 175 | Finally, we need to configure Doom Emacs to use the proper packages and set some |
| 180 | set some variables and functions. | 176 | variables and functions. |
| 181 | 177 | ||
| 182 | #+begin_src sh | 178 | #+begin_src sh |
| 183 | nano ~/.doom.d/config.el | 179 | nano ~/.doom.d/config.el |
| @@ -275,14 +271,12 @@ Be sure to sync Doom to update the current configurations. | |||
| 275 | doom sync | 271 | doom sync |
| 276 | #+end_src | 272 | #+end_src |
| 277 | 273 | ||
| 278 | If you have Doom open, execute =SPC h r r= to reload the new | 274 | If you have Doom open, execute =SPC h r r= to reload the new configurations. |
| 279 | configurations. | ||
| 280 | 275 | ||
| 281 | * Initial Sync | 276 | * Initial Sync |
| 282 | 277 | ||
| 283 | Once you have configured all of the relevant files, you can perform an | 278 | Once you have configured all of the relevant files, you can perform an initial |
| 284 | initial sync. Note that you can perform syncing within Mu4e itself after | 279 | sync. Note that you can perform syncing within Mu4e itself after this. |
| 285 | this. | ||
| 286 | 280 | ||
| 287 | #+begin_src sh | 281 | #+begin_src sh |
| 288 | mbsync -aV | 282 | mbsync -aV |
| @@ -299,11 +293,11 @@ The emails will now to be ready to use! | |||
| 299 | 293 | ||
| 300 | * Screenshots | 294 | * Screenshots |
| 301 | 295 | ||
| 302 | You can now launch Doom and open Mu4e with =SPC o m=. You can also | 296 | You can now launch Doom and open Mu4e with =SPC o m=. You can also explore the |
| 303 | explore the Mu4e options with =SPC : mu4e=. | 297 | Mu4e options with =SPC : mu4e=. |
| 304 | 298 | ||
| 305 | The home page shows various options and metadata about the account | 299 | The home page shows various options and metadata about the account you've |
| 306 | you've opened. | 300 | opened. |
| 307 | 301 | ||
| 308 | #+caption: Mu4e Home Page | 302 | #+caption: Mu4e Home Page |
| 309 | [[https://img.cleberg.net/blog/20240418-mu4e/mu4e.png]] | 303 | [[https://img.cleberg.net/blog/20240418-mu4e/mu4e.png]] |
content/blog/2024-05-03-ubuntu-on-macos.org +38 −42
| @@ -3,24 +3,24 @@ | |||
| 3 | #+description: Learn how to run Linux machines as applications on macOS with minimal hassle. | 3 | #+description: Learn how to run Linux machines as applications on macOS with minimal hassle. |
| 4 | #+slug: ubuntu-on-macos | 4 | #+slug: ubuntu-on-macos |
| 5 | 5 | ||
| 6 | Being a macOS user who previously used Linux for many years, I often | 6 | Being a macOS user who previously used Linux for many years, I often find myself |
| 7 | find myself searching for alternatives to the Linux-native tools and | 7 | searching for alternatives to the Linux-native tools and methods that I had |
| 8 | methods that I had become used to over the years. | 8 | become used to over the years. |
| 9 | 9 | ||
| 10 | Luckily, there's an option to simply use Linux directly on your macOS | 10 | Luckily, there's an option to simply use Linux directly on your macOS device |
| 11 | device without having to boot the whole device into Linux or having to | 11 | without having to boot the whole device into Linux or having to SSH into another |
| 12 | SSH into another Linux machine. | 12 | Linux machine. |
| 13 | 13 | ||
| 14 | In this post, I use [[https://orbstack.dev/][OrbStack]] to create an | 14 | In this post, I use [[https://orbstack.dev/][OrbStack]] to create an Ubuntu Linux machine to take advantage |
| 15 | Ubuntu Linux machine to take advantage of the Linux system. | 15 | of the Linux system. |
| 16 | 16 | ||
| 17 | ** Installing OrbStack | 17 | ** Installing OrbStack |
| 18 | 18 | ||
| 19 | OrbStack has a [[https://orbstack.dev/download][download page]] if you | 19 | OrbStack has a [[https://orbstack.dev/download][download page]] if you prefer to use =*.dmg= files to install |
| 20 | prefer to use =*.dmg= files to install applications. | 20 | applications. |
| 21 | 21 | ||
| 22 | Personally, I prefer to install everything through Homebrew. For | 22 | Personally, I prefer to install everything through Homebrew. For OrbStack, run |
| 23 | OrbStack, run the following to install the application via Homebrew: | 23 | the following to install the application via Homebrew: |
| 24 | 24 | ||
| 25 | #+begin_src sh | 25 | #+begin_src sh |
| 26 | brew install orbstack | 26 | brew install orbstack |
| @@ -28,72 +28,68 @@ brew install orbstack | |||
| 28 | 28 | ||
| 29 | ** Creating a Linux Machine | 29 | ** Creating a Linux Machine |
| 30 | 30 | ||
| 31 | Once installed, you can launch OrbStack and create a Linux machine in a | 31 | Once installed, you can launch OrbStack and create a Linux machine in a matter |
| 32 | matter of seconds. The creation dialog defaults to Ubuntu. | 32 | of seconds. The creation dialog defaults to Ubuntu. |
| 33 | 33 | ||
| 34 | #+caption: OrbStack's Linux Machine Creation Page | 34 | #+caption: OrbStack's Linux Machine Creation Page |
| 35 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/create.png]] | 35 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/create.png]] |
| 36 | 36 | ||
| 37 | ** Launching the Machine | 37 | ** Launching the Machine |
| 38 | 38 | ||
| 39 | Once created, the dialog will close and you will be presented with your | 39 | Once created, the dialog will close and you will be presented with your new list |
| 40 | new list of machines. Simply double-click on a machine to run it. | 40 | of machines. Simply double-click on a machine to run it. |
| 41 | 41 | ||
| 42 | When you run the machine for the first time, it may warn you that a | 42 | When you run the machine for the first time, it may warn you that a program is |
| 43 | program is attempting to run a shell script. You can choose to manually | 43 | attempting to run a shell script. You can choose to manually inspect this shell |
| 44 | inspect this shell script via the provided path if you wish. When you're | 44 | script via the provided path if you wish. When you're comfortable with the |
| 45 | comfortable with the script, you can toggle the | 45 | script, you can toggle the =Suppress this message permanently= button and click |
| 46 | =Suppress this message permanently= button and click OK to run the | 46 | OK to run the machine. |
| 47 | machine. | ||
| 48 | 47 | ||
| 49 | #+begin_quote | 48 | #+begin_quote |
| 50 | *Quick Tip*! | 49 | *Quick Tip*! |
| 51 | 50 | ||
| 52 | You will always be able to launch the OrbStack application and control | 51 | You will always be able to launch the OrbStack application and control the |
| 53 | the machine via the Machines page, but you can also use the OrbStack | 52 | machine via the Machines page, but you can also use the OrbStack icon in the |
| 54 | icon in the macOS menu bar to quickly control the machine without | 53 | macOS menu bar to quickly control the machine without launching OrbStack itself. |
| 55 | launching OrbStack itself. | ||
| 56 | #+end_quote | 54 | #+end_quote |
| 57 | 55 | ||
| 58 | ** Working in Linux | 56 | ** Working in Linux |
| 59 | 57 | ||
| 60 | Once successful, OrbStack will launch your default terminal and log you | 58 | Once successful, OrbStack will launch your default terminal and log you into the |
| 61 | into the Linux machine you created above. | 59 | Linux machine you created above. |
| 62 | 60 | ||
| 63 | In the example below, we can see that the machine is using | 61 | In the example below, we can see that the machine is using =Linux ubuntu 6.9.6= |
| 64 | =Linux ubuntu 6.9.6= and operates similar to a fresh Ubuntu install on | 62 | and operates similar to a fresh Ubuntu install on bare metal. |
| 65 | bare metal. | ||
| 66 | 63 | ||
| 67 | #+caption: Ubuntu CLI | 64 | #+caption: Ubuntu CLI |
| 68 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/cli.png]] | 65 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/cli.png]] |
| 69 | 66 | ||
| 70 | You can also click the machine's folder icon in OrbStack to open the | 67 | You can also click the machine's folder icon in OrbStack to open the machine's |
| 71 | machine's file system within macOS's native Files app. Within Files, you | 68 | file system within macOS's native Files app. Within Files, you can double-click |
| 72 | can double-click to open any files and they will open in the macOS | 69 | to open any files and they will open in the macOS defaults for those file types |
| 73 | defaults for those file types (e.g., TextEdit). | 70 | (e.g., TextEdit). |
| 74 | 71 | ||
| 75 | #+caption: Ubuntu Files | 72 | #+caption: Ubuntu Files |
| 76 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/files.png]] | 73 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/files.png]] |
| 77 | 74 | ||
| 78 | Here's an example of opening the =test.md= file in the screenshot above, | 75 | Here's an example of opening the =test.md= file in the screenshot above, which |
| 79 | which defaults to opening in Xcode on my system. | 76 | defaults to opening in Xcode on my system. |
| 80 | 77 | ||
| 81 | #+caption: Ubuntu Files | 78 | #+caption: Ubuntu Files |
| 82 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/xcode.png]] | 79 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/xcode.png]] |
| 83 | 80 | ||
| 84 | *** Test Examples | 81 | *** Test Examples |
| 85 | 82 | ||
| 86 | As a quick example of the system, I installed =neofetch=, switched to | 83 | As a quick example of the system, I installed =neofetch=, switched to the =zsh= |
| 87 | the =zsh= shell, and ran a few common commands. | 84 | shell, and ran a few common commands. |
| 88 | 85 | ||
| 89 | #+caption: Test Examples | 86 | #+caption: Test Examples |
| 90 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/test.png]] | 87 | [[https://img.cleberg.net/blog/20240503-ubuntu-on-macos/test.png]] |
| 91 | 88 | ||
| 92 | ** Thoughts | 89 | ** Thoughts |
| 93 | 90 | ||
| 94 | The installation, creation, and launch processes are seamless and | 91 | The installation, creation, and launch processes are seamless and provide an |
| 95 | provide an easy way to test or use Linux on macOS with little to no | 92 | easy way to test or use Linux on macOS with little to no hassle. |
| 96 | hassle. | ||
| 97 | 93 | ||
| 98 | The shell and file integrations are incredibly snappy and I have not | 94 | The shell and file integrations are incredibly snappy and I have not |
| 99 | experienced any lag so far. Further, being able to open files in the | 95 | experienced any lag so far. Further, being able to open files in the |
content/blog/2024-06-19-deprecated-trusted-gpg-fix.org +33 −35
| @@ -5,8 +5,8 @@ | |||
| 5 | 5 | ||
| 6 | ** System Warning | 6 | ** System Warning |
| 7 | 7 | ||
| 8 | When running an update on an Ubuntu system, you may have run into a | 8 | When running an update on an Ubuntu system, you may have run into a system |
| 9 | system warning that looks like the example below. | 9 | warning that looks like the example below. |
| 10 | 10 | ||
| 11 | #+begin_src txt | 11 | #+begin_src txt |
| 12 | W: https://dl.yarnpkg.com/debian/dists/stable/InRelease: Key is stored in legacy | 12 | W: https://dl.yarnpkg.com/debian/dists/stable/InRelease: Key is stored in legacy |
| @@ -14,34 +14,33 @@ trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in | |||
| 14 | apt-key(8) for details. | 14 | apt-key(8) for details. |
| 15 | #+end_src | 15 | #+end_src |
| 16 | 16 | ||
| 17 | While this example references the =yarn= package, the warning message is | 17 | While this example references the =yarn= package, the warning message is the |
| 18 | the same for any repository using the deprecated =trusted.gpg= key ring. | 18 | same for any repository using the deprecated =trusted.gpg= key ring. |
| 19 | 19 | ||
| 20 | The issue arises from managing keys with the =apt-key= command, which | 20 | The issue arises from managing keys with the =apt-key= command, which utilizes |
| 21 | utilizes the =/etc/apt/trusted.gpg= file by default. Instead, Ubuntu has | 21 | the =/etc/apt/trusted.gpg= file by default. Instead, Ubuntu has moved to |
| 22 | moved to managing key rings with individual =.gpg= files in the | 22 | managing key rings with individual =.gpg= files in the =/etc/apt/trusted.gpg.d/= |
| 23 | =/etc/apt/trusted.gpg.d/= directory. | 23 | directory. |
| 24 | 24 | ||
| 25 | To fix this issue, let's check to see which keys are using the | 25 | To fix this issue, let's check to see which keys are using the =trusted.gpg= key |
| 26 | =trusted.gpg= key ring and move them into their own dedicated key ring. | 26 | ring and move them into their own dedicated key ring. |
| 27 | 27 | ||
| 28 | ** Finding All Keys in the Keyring | 28 | ** Finding All Keys in the Keyring |
| 29 | 29 | ||
| 30 | Let's start by simply listing the keys used by the =apt= commands. To do | 30 | Let's start by simply listing the keys used by the =apt= commands. To do this, |
| 31 | this, run the following command. | 31 | run the following command. |
| 32 | 32 | ||
| 33 | #+begin_src sh | 33 | #+begin_src sh |
| 34 | sudo apt-key list | 34 | sudo apt-key list |
| 35 | #+end_src | 35 | #+end_src |
| 36 | 36 | ||
| 37 | This command will show an output similar to the one below. You may see | 37 | This command will show an output similar to the one below. You may see |
| 38 | additional keys in the =/etc/apt/trusted.gpg.d/= directory - this is | 38 | additional keys in the =/etc/apt/trusted.gpg.d/= directory - this is where we |
| 39 | where we will be moving any keys currently found in the =trusted.gpg= | 39 | will be moving any keys currently found in the =trusted.gpg= key ring. |
| 40 | key ring. | ||
| 41 | 40 | ||
| 42 | In the below example, we can see that this system has four different GPG | 41 | In the below example, we can see that this system has four different GPG keys |
| 43 | keys stored within the =trusted.gpg= key ring. Let's go ahead and move | 42 | stored within the =trusted.gpg= key ring. Let's go ahead and move them into |
| 44 | them into their own files. | 43 | their own files. |
| 45 | 44 | ||
| 46 | #+begin_src txt | 45 | #+begin_src txt |
| 47 | Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead | 46 | Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead |
| @@ -73,24 +72,24 @@ uid [ unknown] nginx signing key <signing-key-3@nginx.com> | |||
| 73 | 72 | ||
| 74 | *** Exporting Keys to New Files | 73 | *** Exporting Keys to New Files |
| 75 | 74 | ||
| 76 | Now that we know the keys, we will need to move them into their own key | 75 | Now that we know the keys, we will need to move them into their own key ring. We |
| 77 | ring. We can do this by copying the last eight (8) characters from the | 76 | can do this by copying the last eight (8) characters from the key's signature |
| 78 | key's signature and exporting it from this key ring into its own. | 77 | and exporting it from this key ring into its own. |
| 79 | 78 | ||
| 80 | Using the yarn example from the beginning, here's the command to move | 79 | Using the yarn example from the beginning, here's the command to move this key |
| 81 | this key into its own key ring. | 80 | into its own key ring. |
| 82 | 81 | ||
| 83 | #+begin_src sh | 82 | #+begin_src sh |
| 84 | sudo apt-key export 86E50310 | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/yarn.gpg | 83 | sudo apt-key export 86E50310 | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/yarn.gpg |
| 85 | #+end_src | 84 | #+end_src |
| 86 | 85 | ||
| 87 | You can repeat this process for any other keys, such as the =nginx= keys | 86 | You can repeat this process for any other keys, such as the =nginx= keys in the |
| 88 | in the example above. | 87 | example above. |
| 89 | 88 | ||
| 90 | *** Cleaning Up | 89 | *** Cleaning Up |
| 91 | 90 | ||
| 92 | If you run =sudo apt-key list= again, you should see the keys within | 91 | If you run =sudo apt-key list= again, you should see the keys within their own |
| 93 | their own key rings: | 92 | key rings: |
| 94 | 93 | ||
| 95 | #+begin_src txt | 94 | #+begin_src txt |
| 96 | /etc/apt/trusted.gpg.d/nginx-archive-keyring.gpg | 95 | /etc/apt/trusted.gpg.d/nginx-archive-keyring.gpg |
| @@ -117,17 +116,16 @@ sub rsa4096 2019-01-02 [S] [expires: 2026-01-23] | |||
| 117 | sub rsa4096 2019-01-11 [S] [expires: 2026-01-23] | 116 | sub rsa4096 2019-01-11 [S] [expires: 2026-01-23] |
| 118 | #+end_src | 117 | #+end_src |
| 119 | 118 | ||
| 120 | Once you have verified that the keys are valid and stored in their own | 119 | Once you have verified that the keys are valid and stored in their own key |
| 121 | key rings, you can archive the =trusted.gpg= file and run a system | 120 | rings, you can archive the =trusted.gpg= file and run a system update to test |
| 122 | update to test the new files. | 121 | the new files. |
| 123 | 122 | ||
| 124 | #+begin_src sh | 123 | #+begin_src sh |
| 125 | sudo mv /etc/apt/trusted.gpg /etc/apt/trusted.gpg.bkp | 124 | sudo mv /etc/apt/trusted.gpg /etc/apt/trusted.gpg.bkp |
| 126 | sudo apt update | 125 | sudo apt update |
| 127 | #+end_src | 126 | #+end_src |
| 128 | 127 | ||
| 129 | Once you've verified that updates work as expected and that the keys are | 128 | Once you've verified that updates work as expected and that the keys are working |
| 130 | working as intended, you can delete the =.bkp= file created above. If | 129 | as intended, you can delete the =.bkp= file created above. If you're storing |
| 131 | you're storing keys that are not easily re-attainable, I suggest keeping | 130 | keys that are not easily re-attainable, I suggest keeping the =.bkp= file stored |
| 132 | the =.bkp= file stored in a safe location until you are positive that | 131 | in a safe location until you are positive that you no longer need it. |
| 133 | you no longer need it. | ||
content/blog/2024-07-11-emacs-on-ipad.org +24 −28
| @@ -5,25 +5,23 @@ | |||
| 5 | #+slug: emacs-on-ipad | 5 | #+slug: emacs-on-ipad |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | This post describes the process to install and use Emacs on the iPad Air | 8 | This post describes the process to install and use Emacs on the iPad Air 13-inch |
| 9 | 13-inch (M2). The iPad used in this post is running iPadOS 17.6. | 9 | (M2). The iPad used in this post is running iPadOS 17.6. |
| 10 | 10 | ||
| 11 | ** Shell Application | 11 | ** Shell Application |
| 12 | 12 | ||
| 13 | In order to use Emacs on an iPad, you will need a terminal emulator | 13 | In order to use Emacs on an iPad, you will need a terminal emulator application. |
| 14 | application. I recommend | 14 | I recommend [[https://apps.apple.com/us/app/ish-shell/id1436902243][iSH]], since it runs a version of Alpine Linux within the app itself |
| 15 | [[https://apps.apple.com/us/app/ish-shell/id1436902243][iSH]], since it | 15 | and will allow you to install packages that you need. |
| 16 | runs a version of Alpine Linux within the app itself and will allow you | ||
| 17 | to install packages that you need. | ||
| 18 | 16 | ||
| 19 | #+caption: iSH Application | 17 | #+caption: iSH Application |
| 20 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/ish.png]] | 18 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/ish.png]] |
| 21 | 19 | ||
| 22 | ** Require Packages | 20 | ** Require Packages |
| 23 | 21 | ||
| 24 | I started by adding the required packages directly within iSH. Emacs | 22 | I started by adding the required packages directly within iSH. Emacs should |
| 25 | should install dependencies by default, but I include a few other | 23 | install dependencies by default, but I include a few other packages that I use |
| 26 | packages that I use in my terminal as well. | 24 | in my terminal as well. |
| 27 | 25 | ||
| 28 | #+begin_src sh | 26 | #+begin_src sh |
| 29 | apk add emacs ripgrep fd findutils | 27 | apk add emacs ripgrep fd findutils |
| @@ -34,39 +32,37 @@ apk add emacs ripgrep fd findutils | |||
| 34 | 32 | ||
| 35 | ** Emacs | 33 | ** Emacs |
| 36 | 34 | ||
| 37 | Once this is complete, you should be able to run Emacs natively on your | 35 | Once this is complete, you should be able to run Emacs natively on your iPad. |
| 38 | iPad. It's effective, but can be slow at times. | 36 | It's effective, but can be slow at times. |
| 39 | 37 | ||
| 40 | I attempted to also install Doom Emacs, which technically worked, but | 38 | I attempted to also install Doom Emacs, which technically worked, but was so |
| 41 | was so incredibly slow and buggy that I was not even able to take | 39 | incredibly slow and buggy that I was not even able to take screenshots. Someone |
| 42 | screenshots. Someone smarter than me could likely get it to work with a | 40 | smarter than me could likely get it to work with a little tinkering. |
| 43 | little tinkering. | ||
| 44 | 41 | ||
| 45 | #+caption: Emacs | 42 | #+caption: Emacs |
| 46 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/emacs.png]] | 43 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/emacs.png]] |
| 47 | 44 | ||
| 48 | *** MELPA | 45 | *** MELPA |
| 49 | 46 | ||
| 50 | You also have to remember to hook up MELPA yourself in the =.emacs= file | 47 | You also have to remember to hook up MELPA yourself in the =.emacs= file to be |
| 51 | to be able to search through their 5700+ packages instead of just ELPA | 48 | able to search through their 5700+ packages instead of just ELPA packages. If |
| 52 | packages. If you don't, you will only have access to ELPA packages like | 49 | you don't, you will only have access to ELPA packages like the ones below. |
| 53 | the ones below. | ||
| 54 | 50 | ||
| 55 | #+caption: package-install | 51 | #+caption: package-install |
| 56 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/melpa.png]] | 52 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/melpa.png]] |
| 57 | 53 | ||
| 58 | Once you have MELPA, you can install packages like the =dashboard= | 54 | Once you have MELPA, you can install packages like the =dashboard= package shown |
| 59 | package shown below. | 55 | below. |
| 60 | 56 | ||
| 61 | #+caption: emacs-dashboard | 57 | #+caption: emacs-dashboard |
| 62 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/dashboard.png]] | 58 | [[https://img.cleberg.net/blog/20240711-emacs-on-ipad/dashboard.png]] |
| 63 | 59 | ||
| 64 | *** Speed | 60 | *** Speed |
| 65 | 61 | ||
| 66 | While Emacs will run on my iPad, it's not perfect. The largest issue on | 62 | While Emacs will run on my iPad, it's not perfect. The largest issue on my iPad |
| 67 | my iPad is speed - loading Emacs takes 6-7 seconds and installing the | 63 | is speed - loading Emacs takes 6-7 seconds and installing the =magit= package |
| 68 | =magit= package took 129 seconds. | 64 | took 129 seconds. |
| 69 | 65 | ||
| 70 | I haven't played around enough to optimize loading times and poke around | 66 | I haven't played around enough to optimize loading times and poke around to see |
| 71 | to see why the network requests take so long, but it's a big enough | 67 | why the network requests take so long, but it's a big enough issue that I |
| 72 | issue that I wouldn't see casual Emacs users dealing with the lag. | 68 | wouldn't see casual Emacs users dealing with the lag. |