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