*Memory MatrixWritings, notes, and data Pages
Categories
Tags
|
Paired Comparison AnalysisThis is a simple paired comparison analysis to compare a list of items amongst themselves to find a ranking for decision making.
#!/usr/bin/env python3
#######################################################
# Paired Comparison Analysis
# webmaster@memorymatrix.cloud
# 25.26.12.2053
#######################################################
import sys
import logging
def create_lists(list_a=None, list_b=None):
"""
Create two lists of items from user input
Args:
list_a (list): Initial items for List A (optional)
list_b (list): Initial items for List B (optional)
Returns:
tuple: Two lists (A and B), populated with items
Raises:
TypeError: If invalid items are provided
"""
try:
if list_a is None:
list_a = []
if list_b is None:
list_b = []
# Populate List A if not provided
while True:
item = input("Enter an item for List A (press Enter to stop): ")
if not item:
break
list_a.append(str(item))
# Copy List A to List B
list_b = list(list_a)
logging.info("Lists created successfully")
return list_a, list_b
except KeyboardInterrupt:
print("\nUser interrupted input")
sys.exit(1)
except Exception as e:
logging.error(f"Error creating lists: {str(e)}")
raise
def count_preferences(comparison_results):
"""
Count how many times each item was preferred
Args:
comparison_results (list): List of tuples from compare_items()
Returns:
dict: Dictionary mapping items to their preference counts
Raises:
ValueError: If invalid results are provided
"""
try:
if not comparison_results:
raise ValueError("No comparison results provided")
# Initialize count dictionary
counts = {}
for result in comparison_results:
preferred_item = result[2]
if preferred_item == 1:
counts[result[0]] = counts.get(result[0], 0) + 1
elif preferred_item == 2:
counts[result[1]] = counts.get(result[1], 0) + 1
return counts
except Exception as e:
logging.error(f"Error counting preferences: {str(e)}")
raise
def compare_items(list_a, list_b):
"""
Compare unique pairs of items between two lists and store preferences
Args:
list_a (list): First list of items
list_b (list): Second list of items
Returns:
list: Results of comparisons
Raises:
ValueError: If lists are empty or mismatched
"""
try:
if not list_a or not list_b:
raise ValueError("Both lists must contain items")
results = []
# Generate unique pairs (a, b) where a is from A and b is from B
# Skip comparisons where items are the same or already compared in reverse order
for item_a in list_a:
for item_b in list_b:
# Skip self-comparisons and reverse comparisons
if item_a == item_b or item_a > item_b: # Using '>' to sort alphabetically
continue
try:
preference = input(f"Compare {item_a} vs {item_b}: "
f"Enter 1 if you prefer {item_a}, "
f"2 if you prefer {item_b}: ")
if not preference.isdigit():
print("Invalid input. Please enter 1 or 2.")
continue
results.append((item_a, item_b, int(preference)))
except KeyboardInterrupt:
print("\nUser interrupted comparison")
return results # Return what we have so far
except Exception as e:
logging.error(f"Error during comparison: {str(e)}")
raise
return results
if __name__ == "__main__":
"""
Main program entry point with command line arguments
"""
try:
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler()]
)
# Get items from command line or user input
if len(sys.argv) >= 2:
list_a = [str(sys.argv[1]), str(sys.argv[2])]
else:
print("No command line arguments provided.")
first_item = input("Enter the first item for List A: ")
list_a = [first_item]
list_b, _ = create_lists(list_a=list_a)
results = compare_items(list_a, list_b)
# Get preference counts
preferences = count_preferences(results)
print("\nComparison Results:")
for res in results:
print(f"Comparing {res[0]} vs {res[1]} - Preferred: {res[2]}")
print("\nPreference Counts:")
for item, count in preferences.items():
print(f"{item} was preferred {count} times")
except IndexError:
# Handle cases where lists are too short
print("Error: Not enough items provided. At least two items required")
sys.exit(1)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
sys.exit(0)
# Unit Tests
# to run this, go the source directory venv/bin folder, and use source ./activate
# then python3 -m pytest script-name.py
def test_create_lists():
"""
Test create_lists function with different scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_default_case(mock_input):
mock_input.side_effect = ['apple', 'banana', '', 'berry']
list_a, list_b = create_lists()
assert len(list_a) == 3
assert list_b == list_a
@patch('builtins.input')
def test_single_item(mock_input):
mock_input.side_effect = ['test', '']
list_a, list_b = create_lists()
assert len(list_a) == 1
assert list_b == list_a
def test_compare_items():
"""
Test compare_items function with various scenarios
"""
def test_count_preferences():
"""
Test count_preferences function with various scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_valid_comparison(mock_input):
mock_input.side_effect = ['1', '2']
results = compare_items(['a'], ['a', 'b'])
assert len(results) == 1
@patch('builtins.input')
def test_invalid_input(mock_input):
mock_input.side_effect = ['3', '1']
results = compare_items(['a'], ['a', 'b'])
assert len(results) == 1
def test_count_preferences():
"""
Test count_preferences function with various scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_valid_comparison(mock_input):
mock_input.side_effect = ['1', '2']
results = compare_items(['a'], ['a', 'b'])
preferences = count_preferences(results)
assert len(preferences) == 1
assert preferences.get('a', 0) == 1
@patch('builtins.input')
def test_multiple_comparisons(mock_input):
mock_input.side_effect = ['2', '1']
list_a = ['apple', 'orange']
list_b = ['pear', 'tomato']
results = compare_items(list_a, list_b)
preferences = count_preferences(results)
assert len(preferences) == 2
assert preferences.get('pear', 0) == 1
assert preferences.get('apple', 0) == 1
Thoughts on AiderWell it has taken a little bit, but thanks to Getting Things Gnome! (GTG!), I installed Aider and Ollama and began some vibe coding. Prior to this, I have written data science code in Python and R and produced some GUI applications for Linux. I also developed some software that is in the Windows store, and produced software for the Windows desktop over the past 15 years or more. The applications that I have in the Microsoft store preceded the advent of the large language model coding assistants. For the Aider Model, I am using Ollama and Deepseek r1 14B runing locally using the CPU. I have a 4 GB Geforce 1650 Super, which is not going to handle very much advanced neural net math. I have used GPT4ALL with unlimited CPU consumption and it caused the system to halt due to overheating. To prevent system overheating with GPT4ALL, I had to set a limit of 3 or 4 cores. Ollama has not done that. Ollama defaults to one thread per physical core, which is very helpful. The system runs run at the top of the thermal limit when waiting for Ollama/deepseek, but it works in a very stable manner. Many times it runs several degrees below the upper critical limits. This is also a function of my system itself which has upgraded CPU from the manufacturer’s installed one, while using the original CPU cooler due to space constraints. My goal is to replace a very large spreadsheet that contained all of the items that I had on my wish list at a specific point in time. I had trouble knowing which item to handle first when there were competing priorities such as home maintenance, vehicle maintenance, vehicle luxury upgrades, vehicle necessities, and so on. I then selected between each item and counted the number of wins for each item. As an example, one item that was on my list for a while was a pack of respirators for working with sawdust, flakes, and similar debris. I had kept putting it off because the projects I was planning to use it with were always on a back burner yet to occur. However, it was one of the top picks because when compared against 59 other items, it received the most votes. One might say that was to be expected. Yet another suprise was the backup collection of motor oil so that rather than only having the next oil change worth of oil, I would now have the next two changes of oil.
I am not sure on what to do with the output code. I was thinking about putting it on GitHub but it seems that GitHub is turning into something akin to the single repository of software code online and the master of it all. That unsettles me somewhat, so once I get the initial version working I will consider my options. My process broke down regarding search and replace blocks, and I had to revisit some earlier documentation of outputs. The way I do this simple. I save each revision in a timestamped notebook entry in either QOwnNotes or Gnote. Gnote is fast and easy, but QOwnNotes allows me to input images and draft these blog entries. QOwnNotes and ZettelkästenI love Joplin, but Joplin seems more like an incredible file cabinet and set of bookshelves. It is possible to link from one note to another, but a Joplin icon appears by that link in the text. It can also be cumbersome to navigate between multiple documents while working on one. Joplin recently added the ability to open documents in a child window which really makes the problem wonderful. QOwnNotes includes an excellent Markdown Cheatsheet that one can open in a tab. I am looking for a solution for the extensive file cabinet, and one for the rough drafting. QOwnNotes syncs with Nextcloud.
This .AppImage file not extract via the normal method. Running the AppImage works, but an extraction to squash-fs fails as it leaves nothing in the folders. It is necessary to run it directly from the .AppImage file. When creating new notes, they automatically receive file names like Note 2025-12-17 20h10s34. From this, I remove the word note and add a title and tags so that the name may serve me well in the future. A local mirror of the source is available on this website. A local mirror of the AppImage file for version 25.12.6 is available on this website. The developers release the source and binaries on Github. The web companion for Firefox and LibreWolf is online, as is the Chrome extension. The web companion features seem to require more scripting than I am comfortable with for them to work. The number of Linux distributions for which for which one may download via official repositories is very impressive. Zettlr remains prettier and more fun to type in, but QOwnNotes builds documents that are ready for a simple copy-paste into the WordPress editor for publishing. Nothing can replace Joplin. Joplin recognizes the reference style links of QOwnNotes, and the preview with preformatted text fields for code copy-pastes perfectly into WordPress. Joplin is a definite winner. Especially with the MDI interface. I tried all these apps, and settled back on Joplin, but Zettler is fun to type in. Zettlr is for making a book, and Joplin is for making a reference library. All of this experimentation leads to me deciding to use Joplin better. Zettlr makes it easy to link existing notes by simply starting to type. The readability feature in Zettlr is also very helpful and helps me focus. Joplin can also use Zettlr’s footnote features. This entry may have meandered a bit. I have settled on Joplin or organizing and remembering and and Zettlr for crafting. I will post completed pieces via Joplin preview to WordPress. This post used Joplin 3.4.12 on Debian 12 and Zettlr 3.6.0. Picking a tool for zettelkastenIt is a very challenging thing to pick a tool to invest time into building a personal knowledgebase. I have used numerous tools over the years and collected a huge number of documents and notes. Logseq integrates with Zotero which might prove useful due the gigabytes of material that I have stored there. My plan was always to start writing sometime in the future. All of that material would be analyzed, quoted, and used to support some argument. Zettlr offers the most typerwriter like view, and lacks some of the more advanced features. It is therefore the one that I am going to select for document construction. The simplicity and feature set of the program has proven itself conducive to my needs. Joplin will continue to play a role as a my giant syncronized and backed up file cabinet. Discovering ZettelkästenVia an advertisement there, I discovered https://www.warp.dev/code which looks like an most incredible resource. That may be how applications like Trillium have such incredible documentation and coding. There are 271 contributors, and the documentation and features are incredible and beyond anything else I have seen in a note taking application. This piece of software and the mind blowing quality of the documentation and feature sets has made me reconsider Deepin with the local integration and Deepin IDE. The problem is that the Trillium notes are in a database, whereas Obsidian’s are in mark down. I discovered Zettlr, whose notes are also in Markdown, and discuss that below.. I discovered https://www.zettlr.com/ from a discussion at https://www.xda-developers.com/found-open-source-app-like-obsidian-except-its-better/. From that, I discovered Zettelkästen. More specifically, I learned what it was via Zettlr. The Zettelkasten method involves cross-referencing one’s knowledge base so that one can find relationships between concepts and create a living knowledgebase with minimal forgetfulness.1 Zettlr contains the ability to insert snippets using variables for the date, time, and unique ID numbers. This is something that I had been trying to do of my own accord using various applications over the years. Obsidian has a great preview that one can use to directly copy to blogs and product great entries with links intact. It looks like Obsidian took Trilium’s preview and Zettlr’s markdown and file management to create their application. All three share a very similar sidebar and navigation motif. I consider Obsidian to be like many Minecraft modification developers in recent years. They take a lot of permissively licensed opensource software and then wrap it in an all rights reserved vague statement and do not share any code or redistribution rights. Many minecraft mods say all rights reserved, which is not really a license. They incorporate and link other libraries. Java itself uses a classpath exception so they do not become GPL because of that, however when the mods rely on other libraries that are GPL, such as other mods, and then hide behind “all rights reserved” it really breaks my heart. One would think they would want their mods available at many different sites and not only the website they uploaded them too. Electron is MIT licensed. This is not an accusation. This is my opinion. I suspect Obsidian used Trilium notes and possibly Zettlr code and is not compliant with the GPL. That is my opinion only. Trilium notes even comes with server software. The Obsidian Webclipper is great. Yet it irritates me to no end that an open source foundation, like Electron, and possibly some of the precursors of Obsidian, made the way to a piece of software that says you cannot even redistribute the binaries. They could go out of business, but with binaries around, people could use that great software for ages. The situation is contrary to the Linux ethos. I could be wrong, and they pulled their code from Memos, which has a very similiar interface. The Memos code is at https://github.com/usememos/memos. Memos is another project sponsored by Warp. I am not accusing Obsidian. Logseq is another GPL project with a great deal of similar features and buttons, and is available at https://github.com/logseq/logseq. I am stating that it is very strange, and perhaps some AI agents are using GPL code and the downstream products are not GPL as they should be, but that is my opinion only.
Indeed implements arbitrationIndeed emailed me on 3 September 2025 with details that they changed their terms of service. This is what their email said:
No doubt this is because the Supreme Court of the United States made it equally possible for Caucasians to sue for discrimination and they want to block the class action lawsuits they likely deserve. I have not logged in since that date, since I do not accept an arbitration agreement with them. Agreeing to have no class action with a primary gatekeeper to employment is not a wise decision. Countless people were part of class actions against discriminators such as American Freight and others. It is not my intent to dwell on the past. This is here as a mile marker. Joplin AppImage IntegrationJoplin is the beautiful open source replacement for Evernote. Once upon a time, Evernote was a dream app, but then they sent out an atrocious terms of service change after turning their user interface into drab garbage compared to the old colorful beauty that existed in version 4 and before. Joplin is fully functional and syncs on every platform. They also provide a pure APK for download so that one can install it on LineageOS or other nongeminized Android system. It offers full digital sovereignty. One helpful tip that I spent a long time searching before learning, is that you can customize an image per notebook name, by right-clicking on the notebook, choosing edit, and then selecting an emoji. Each notebook can have a different emoji as the icon. Here is the procedure to integrate it into the Linux desktop. Notably, the icon is still the beautiful blue icon, and not the atrocious black and white one that has taken center stage on Windows versions of the app. chmod +x Joplin-3.4.12.AppImage ./Joplin-3.4.12.AppImage --appimage-extract mv squashfs-root joplin-3.4.12 mv joplin-3.4.12 $HOME/Apps cp $HOME/Apps/joplin-3.4.12/joplin.desktop $HOME/.local/share/applications kate $HOME/.local/share/applications/joplin.desktop Edit the file to say the following, but with $HOME replaced by the actual home directory of the relevant user: [Desktop Entry] Name=Joplin Exec=$HOME/Apps/joplin-3.4.12/joplin --no-sandbox %U Terminal=false Type=Application Icon=$HOME/Apps/joplin-3.4.12/joplin.png StartupWMClass=Joplin X-AppImage-Version=3.4.12 MimeType=x-scheme-handler/joplin; Comment=Joplin for Desktop Categories=Office; Local download links: The last version that worked on OSX Catalina was 3.2.12. LibreWolf 145 & Integrated AppImageLibreWolf is a fork of Firefox that removes many of Mozilla’s bad decisions.1 A mirror of LibreWolf 145.0.1-2.x86_64 appimage is available here. Debian stable requires one to use a format other than the LibreWolf repo because as of 23 November, 2025 their site says the following: sudo apt update && sudo apt install extrepo -y sudo extrepo enable librewolf sudo apt update && sudo apt install librewolf -y Extrarepo exists only in Sid, which makes it unsuitable for Bookworm, or other stable Debian editions. Adding Sid repos can turn Debian into something akin to a rolling distribution but it can cause problems if one wants older software. To integrate the linked appimage into the operating system, take the following actions.2 ./LibreWolf.x86_64.AppImage --appimage-extract mv squashfs-root librewolf-145.0.1-2 mv librewolf-145.0.1-2 $HOME/Apps cp $HOME/Apps/librewolf-145.0.1-2/io.gitlab.LibreWolf.desktop $HOME/.local/share/applications Then, modify the four lines in $HOME/.local/share/applications/io.gitlab.LibreWolf.desktop that say exec. Those lines need to reflect the path where the executable resides. I was working on this with Obsidian and preparing to archive the appimage on this website when I ran into a snag. The Obsidian .desktop referenced the AppRun from the AppImage whereas Librewolf referenced the executable named librewolf. After resolving this, I checked the licenses. Obsidian distributes software that is under the Apache License. That license allows one to add other requirements to their additions to the software. Their additional term is that you may not redistribute their software. They are even more onerous that IBM was with Lotus Symphony 3. Lotus Symphony 3 was an office suite built on Open Office that had an excellent tabbed document interface. It was a beautiful interface that Open Office should have incorporated, but for some reason they did not. The Symphony 3 license allows you to redistribute on physical disc to your friends and family, but not via internet website. Obsidian says no to redistribution at all. I was using Obsidian extensively on all my mobile devices, but will have to discontinue using it now. I have no interest in building open source machines with open source operating systems and having software that does not allow you to mirror it. ./Obsidian-1.10.3.AppImage --appimage-extract mv squashfs-root Obsidian-1.10.3 mv Obsidian-1.10.3 $HOME/Apps cp $HOME/Apps/Obsidian-1.10.3/obsidian.desktop $HOME/.local/share/applications Modify the exec line in $HOME/.local/share/applications/obsidian.desktop to reflect the path where the AppImage contents appear. The exec should point to the application binary and not the AppRun file. e.g. $HOME/Apps/Obsidian-1.10.3/obsidian I will leave this here for memory and education, but will discontinue the use of Obsidian since its future as an ongoing concern is limited to their availability of their website as a distribution channel. That does not bode well. Symphony 3 (1.3 on Linux) is nearly extinct, but one can still run it on old virtual machines.
My refined direction is digital sovereigntyMy refined direction is digital sovereignty via the old paths with a goal of writing at least one article per week. The complexity of the articles will change because many projects are planned for the long term, but getting started on them takes a very long time.. I setup a RAID 5 in my old computer using new Western Digital 2 TB drives. In this case, the old machine is a Hewlett Packard Z600. The computer is very old in computer years. It has 12 Cores via dual Intel(R) Xeon(R) CPUs of model X5675 at 3.07GHz. [1] The prices on these on eBay have gone through the roof for old desktops computers of many types. One can easily find conversations about hard drives from three or four years discussing prices of $15 per terabyte. Now they are over $30 per terabyte. I had purchased a used 2TB drive to use as Samba share space in the machine, and it went bad and locked into read-only mode within about a year. In deciding whether to buy used or new drives, I came to the conclusion that on an annual basis, one ends up spending the same or more via used drives than they do with new drives. Were one to purchase used drives, twice as many need to be acquired which eliminates the financial benefit while increasing one’s stress. I could not remember my Vivaldi sync password despite creating the account only a couple of days ago. I tried several times to remember it, and then connections to vivaldi.net started timing out. It seems to me that they blocked me. If that had happened with the ability to access my email, it would have been a real issue. Because of this, I need to work on a more digitally sovereign approach here. The extensions I use for Vivaldi include the Obsidian Web Clipper, Joplin Web Clipper, Zotero Connector, floccus bookmarks sync, SingleFile, and uMatrix. For LibreWolf, my extensions are Obsidian Web Clipper, SingleFile, Copy PlainText, floccus bookmarks sync, Joplin Web Clipper, Search by Image, Tree Style Tab, uMatrix, Undo Close Tab, and Web Archives.
Running old versions of Java MinecraftOne source for the Java 8 (1.8) runtime is the Oracle Archives page. Another helpful one is the standard Java download page for the desktop Java Runtime Environment, JRE. I downloaded the Linux x86 (32-bit) version even though the host is a 64bit Linux. The reason for that is that at some point in the point in the past Minecraft and various mods and the Forge loader required a 32 bit Java virtual machine (JVM). It was so problematic to install both 64bit and 32bit via the package managers and manually configure them, that I developed a practice of installing 32-bit Linux so that the Java in the repository would also be 32bit and then everything would be fin. It was much easier to run 32-bit Java and 32-bit Wine on a 32-bit operating system than reconfigure everything and try to switch between them depending on what was running. I extracted the zip file from Oracle and then ran the Minecraft server instance with the following command.
Running the program that way worked very well. .ssh config for Windows and LinuxThe ~/.ssh/config file works for OpenSSH on Windows and for SSH on Linux. To prevent disconnects, add the keepalive messages for all hosts. For specific hosts that use a specific key type, such as RSA on CentOS 6, add the specific algorithm via the HostkeyAlgorithms + functionality. To add a private key for SSH key logins, add the IdentityFile line. it is possible to allow the ssh-rsa algorithms on both outgoing and incoming connections for all hosts. The PubkeyAcceptedAlgorithms functionality is which key can be used to log into the host the config file sits on. the ForwardX11 setting sits on Linux hosts and not on Windows.. example ~/.ssh/config
IdentityFile ~/.ssh/Minecraft-Micro.pem
Host *
ServerAliveInterval 40
Host 192.168.0.0
HostkeyAlgorithms +ssh-rsa
ForwardX11 yes
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa
Switch a data volume on LinuxHow to move /var/www/html/mydata/ to a new disk: 1. fdisk /dev/nvme4n1 [_] Expand 7 to show fstab options |