<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: raddevus</title>
    <description>The latest articles on Forem by raddevus (@raddevus).</description>
    <link>https://forem.com/raddevus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F208089%2F91d9eb8c-0e0b-4600-9be6-e11c67d0cdc2.png</url>
      <title>Forem: raddevus</title>
      <link>https://forem.com/raddevus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/raddevus"/>
    <language>en</language>
    <item>
      <title>Meme Monday</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Mon, 02 Mar 2026 18:31:16 +0000</pubDate>
      <link>https://forem.com/raddevus/meme-monday-5d21</link>
      <guid>https://forem.com/raddevus/meme-monday-5d21</guid>
      <description>&lt;h3&gt;
  
  
  Meme Monday
&lt;/h3&gt;

&lt;p&gt;I can't wait all day for this site to start the Meme Monday post, so here it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jou0yrwujmjhfge1pbw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jou0yrwujmjhfge1pbw.jpg" alt=" " width="680" height="675"&gt;&lt;/a&gt;&lt;/p&gt;






&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flegn1w5qodlzn4vkfmfl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flegn1w5qodlzn4vkfmfl.jpg" alt=" " width="784" height="1168"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;&lt;br&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vw6si9leie3lwb3nd23.png" alt=" " width="548" height="469"&gt;&lt;br&gt;&lt;br&gt;

&lt;br&gt;&lt;br&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq01upvoyynhrf23u7axs.jpeg" alt=" " width="640" height="527"&gt;





</description>
      <category>community</category>
      <category>discuss</category>
      <category>programming</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Longest amount of time on any project?</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Mon, 20 Oct 2025 20:50:36 +0000</pubDate>
      <link>https://forem.com/raddevus/longest-amount-of-time-on-any-project-420c</link>
      <guid>https://forem.com/raddevus/longest-amount-of-time-on-any-project-420c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ii044wya1ys6h37s53y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ii044wya1ys6h37s53y.png" alt=" " width="800" height="581"&gt;&lt;/a&gt;&lt;br&gt;
(from &lt;a href="https://x.com/aarondotdev/status/1978478524916015513" rel="noopener noreferrer"&gt;https://x.com/aarondotdev/status/1978478524916015513&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  More Details From Wikipedia
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64hn7om55wtvm74d7hwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64hn7om55wtvm74d7hwh.png" alt=" " width="653" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Makes Me Question Myself As A Dev
&lt;/h3&gt;

&lt;p&gt;"Hmm...I don't know if I've ever actually really focused entirely on project for 2 years (2080 hours x 2) on one project.&lt;br&gt;
I've put a lot of hours into my C'YaPass (FOSS Password manager - &lt;a href="https://github.com/raddevus/cyapass-kotlin" rel="noopener noreferrer"&gt;source at GitHub&lt;/a&gt;.) program but realistically it isn't 4160 hours.&lt;/p&gt;

&lt;p&gt;I have a couple of work projects that I've worked on for that many hours over 10 years probably. But again, I don't think I've ever focused on one project for 2 years straight.&lt;/p&gt;

&lt;h3&gt;
  
  
  How about you?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Have you worked on any Work Projects with that kind of focus?&lt;/li&gt;
&lt;li&gt;Have you worked on any Personal Projects with that kind of focus?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I thinking of "intense focus" (2 years straight) especially, but please share any experiences you've had.&lt;/p&gt;

</description>
      <category>career</category>
      <category>devjournal</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Why No New (Quality) Android Programming Books?</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Mon, 23 Sep 2024 18:22:23 +0000</pubDate>
      <link>https://forem.com/raddevus/why-no-new-quality-android-programming-books-4opi</link>
      <guid>https://forem.com/raddevus/why-no-new-quality-android-programming-books-4opi</guid>
      <description>&lt;p&gt;Why haven't there any new books since the great &lt;a href="https://amzn.to/3zCBgsn" rel="noopener noreferrer"&gt;Android Programming Big Nerd Ranch&lt;/a&gt; 5th ed., 2022?&lt;/p&gt;

&lt;p&gt;There have been a lot of changes in the Development Process and in Android Studio over that period of time, but no quality books published on the new changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnx6q1rix8ozt9umbhqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnx6q1rix8ozt9umbhqc.png" alt="Image description" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to try out &lt;a href="https://amzn.to/3BopLVX" rel="noopener noreferrer"&gt;Programming Android With Kotlin&lt;/a&gt; (Jan. 2022) but I haven't seen any other good ones since those two.  &lt;/p&gt;

&lt;p&gt;Have you read any great Android Programming books?  Please share in the comments.&lt;/p&gt;

</description>
      <category>android</category>
      <category>androiddev</category>
      <category>mobile</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>10 Reasons You Should Never Hire a Dev Who Writes a List Article On Dev.To</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Fri, 09 Aug 2024 13:19:57 +0000</pubDate>
      <link>https://forem.com/raddevus/10-reasons-you-should-never-hire-a-dev-who-writes-a-list-article-on-devto-404a</link>
      <guid>https://forem.com/raddevus/10-reasons-you-should-never-hire-a-dev-who-writes-a-list-article-on-devto-404a</guid>
      <description>&lt;h2&gt;
  
  
  10 - Lowest common denominator.
&lt;/h2&gt;

&lt;p&gt;The list article is the easiest of all articles to write and requires the least amount of creativity.  Is that the type of Software Dev you want to work with?  One who takes the easy way out.&lt;/p&gt;

&lt;h2&gt;
  
  
  9 - Attention Getter
&lt;/h2&gt;

&lt;p&gt;The list article is only written to gain attention.  A writer who writes a list article is likely vainglorious and attention-seeking with no substance behind them.  Is this the kind of employee you want working for our company?  &lt;/p&gt;

&lt;p&gt;One who just wants to get attention:  be ready to experience tons of drama if you hire the list article writer.&lt;/p&gt;

&lt;h2&gt;
  
  
  8 - Lack of Creativity
&lt;/h2&gt;

&lt;p&gt;The fact that the dev has chosen to write a list article is proof that they have very little creativity and cannot think of an interesting article that focuses on a specific topic.  Do you want to work with non-creative employee?&lt;/p&gt;

&lt;h2&gt;
  
  
  7 - Boring
&lt;/h2&gt;

&lt;p&gt;Imagine listening to a person who just rambles off a list of facts.  It's so boring.  Do you want to work with boring people?  If you're answer is no, then don't hire a person who writes a list article on Dev.to&lt;/p&gt;

&lt;h2&gt;
  
  
  6 - Doesn't Really Know the Topic
&lt;/h2&gt;

&lt;p&gt;If the person has written a list article, it is because they don't really know how the topic.  Instead, they've just jammed some interesting pieces together in an attempt to create content and post an article.&lt;/p&gt;

&lt;p&gt;However, when the person begins to write code, look out.  The important thing about code is not if you know a bunch of interesting facts, but if you know how to put things together to create a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 - Unlikely Able To Write Complete Solutions
&lt;/h2&gt;

&lt;p&gt;It is unlikely that the person who is writing a list article has the ability and focus to complete an entire app.  Keep in mind that coding (creating software solutions) is not just about writing code.  To create a complete app you will have to do many thing such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use version control system (git)&lt;/li&gt;
&lt;li&gt;translate user stories into the solution&lt;/li&gt;
&lt;li&gt;communicate with other devs&lt;/li&gt;
&lt;li&gt;communicate with project manager&lt;/li&gt;
&lt;li&gt;write unit tests&lt;/li&gt;
&lt;li&gt;deploy your code
And much more.  The person who writes a list article shows only that she can understand small snippets of code in isolation from everything else.  That's not very helpful.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4 - Doesn't Have the Stamina
&lt;/h2&gt;

&lt;p&gt;Writing a list article shows that the dev doesn't have the stamina to do everything it takes to write a complete solution.  Instead, they just want to drop some fast facts and run.  That's not how coding happens at any real company which is trying to produce software solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Probably Written By AI
&lt;/h2&gt;

&lt;p&gt;The list article is probably written by AI anyways.  Most likely if you're reading a list article, it was written by AI, so when you hire the dev who "wrote" the list article they won't understand the content of their article anyways.  Don't be fooled, don't hire a list article writer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Boring, Non-Creative, Drama-Seeker
&lt;/h2&gt;

&lt;p&gt;If you hire a list article writer, you are going to get the trifecta of bad employees:&lt;br&gt;
Boring Non-Creative Drama-Seeker who just wants to stir up drama about which syntax to use but who cannot create great software solutions that people want to use.  &lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Know-It-All
&lt;/h2&gt;

&lt;p&gt;The person who writes the list article will probably be jabbering on about how you "should've used this latest feature of the language" or "oh, you could've used JavaScript Map here...".&lt;br&gt;
Meanwhile you are writing the code that creates the over all solution and rolling your eyes at the list article author's comments. &lt;/p&gt;

&lt;p&gt;I'm sure you'll agree that the list article is the worst of all article types and any dev who writes a list article should be avoided.&lt;/p&gt;

&lt;h2&gt;
  
  
  List Article Upvoter
&lt;/h2&gt;

&lt;p&gt;However, if you are wary of hiring the list article writer, you should be doubly-wary of hiring the List ARticle Upvoter. &lt;br&gt;
If you see a dev who upvotes a list article and says the article is great, it is obvious that they are someone who knows even less than the list article writer.&lt;br&gt;&lt;br&gt;
That's an amazing amount of un-knowledge.  &lt;/p&gt;

&lt;p&gt;These list article upvoters don't even know as much as the list article writers.  Beware!  You don't want these people on your dev project.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The list article is over &amp;amp; should never be written again.  Do not trust list article writers or list article upvoters.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>50 + 50 Basic Linux Commands (100 Total)</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Fri, 12 Jul 2024 15:41:52 +0000</pubDate>
      <link>https://forem.com/raddevus/50-50-basic-linux-commands-100-total-1h75</link>
      <guid>https://forem.com/raddevus/50-50-basic-linux-commands-100-total-1h75</guid>
      <description>&lt;ol&gt;
&lt;li&gt;ls - List directory contents.&lt;/li&gt;
&lt;li&gt;cd - Change the current directory.&lt;/li&gt;
&lt;li&gt;pwd - Print the current working directory.&lt;/li&gt;
&lt;li&gt;mkdir - Create a new directory.&lt;/li&gt;
&lt;li&gt;rmdir - Remove an empty directory.&lt;/li&gt;
&lt;li&gt;rm - Remove files or directories.&lt;/li&gt;
&lt;li&gt;cp - Copy files or directories.&lt;/li&gt;
&lt;li&gt;mv - Move or rename files or directories.&lt;/li&gt;
&lt;li&gt;touch - Create an empty file or update the timestamp of an existing file.&lt;/li&gt;
&lt;li&gt;cat - Concatenate and display file content.&lt;/li&gt;
&lt;li&gt;more - View file content one screen at a time.&lt;/li&gt;
&lt;li&gt;less - View file content with backward movement.&lt;/li&gt;
&lt;li&gt;head - Display the first few lines of a file.&lt;/li&gt;
&lt;li&gt;tail - Display the last few lines of a file.&lt;/li&gt;
&lt;li&gt;echo - Display a line of text.&lt;/li&gt;
&lt;li&gt;man - Display the manual for a command.&lt;/li&gt;
&lt;li&gt;info - Display command information.&lt;/li&gt;
&lt;li&gt;which - Locate a command.&lt;/li&gt;
&lt;li&gt;whereis - Locate the binary, source, and manual page files for a command.&lt;/li&gt;
&lt;li&gt;find - Search for files in a directory hierarchy.&lt;/li&gt;
&lt;li&gt;grep - Search text using patterns.&lt;/li&gt;
&lt;li&gt;sed - Stream editor for filtering and transforming text.&lt;/li&gt;
&lt;li&gt;awk - Pattern scanning and processing language.&lt;/li&gt;
&lt;li&gt;sort - Sort lines of text files.&lt;/li&gt;
&lt;li&gt;uniq - Report or omit repeated lines.&lt;/li&gt;
&lt;li&gt;diff - Compare files line by line.&lt;/li&gt;
&lt;li&gt;cmp - Compare two files byte by byte.&lt;/li&gt;
&lt;li&gt;comm - Compare two sorted files line by line.&lt;/li&gt;
&lt;li&gt;wc - Print newline, word, and byte counts for each file.&lt;/li&gt;
&lt;li&gt;cut - Remove sections from each line of files.&lt;/li&gt;
&lt;li&gt;paste - Merge lines of files.&lt;/li&gt;
&lt;li&gt;tr - Translate or delete characters.&lt;/li&gt;
&lt;li&gt;split - Split a file into pieces.&lt;/li&gt;
&lt;li&gt;join - Join lines of two files on a common field.&lt;/li&gt;
&lt;li&gt;tee - Read from standard input and write to standard output and files.&lt;/li&gt;
&lt;li&gt;xargs - Build and execute command lines from standard input.&lt;/li&gt;
&lt;li&gt;chmod - Change file modes or Access Control Lists.&lt;/li&gt;
&lt;li&gt;chown - Change file owner and group.&lt;/li&gt;
&lt;li&gt;chgrp - Change group ownership.&lt;/li&gt;
&lt;li&gt;ln - Create hard and symbolic links.&lt;/li&gt;
&lt;li&gt;df - Report file system disk space usage.&lt;/li&gt;
&lt;li&gt;du - Estimate file space usage.&lt;/li&gt;
&lt;li&gt;mount - Mount a file system.&lt;/li&gt;
&lt;li&gt;umount - Unmount file systems.&lt;/li&gt;
&lt;li&gt;fsck - File system consistency check and repair.&lt;/li&gt;
&lt;li&gt;mkfs - Build a Linux file system.&lt;/li&gt;
&lt;li&gt;mkswap - Set up a Linux swap area.&lt;/li&gt;
&lt;li&gt;swapon - Enable devices and files for paging and swapping.&lt;/li&gt;
&lt;li&gt;swapoff - Disable devices and files for paging and swapping.&lt;/li&gt;
&lt;li&gt;free - Display amount of free and used memory in the system.&lt;/li&gt;
&lt;li&gt;top - Display Linux tasks.&lt;/li&gt;
&lt;li&gt;htop - Interactive process viewer.&lt;/li&gt;
&lt;li&gt;ps - Report a snapshot of current processes.&lt;/li&gt;
&lt;li&gt;kill - Send a signal to a process.&lt;/li&gt;
&lt;li&gt;pkill - Send a signal to processes based on name and other attributes.&lt;/li&gt;
&lt;li&gt;killall - Kill processes by name.&lt;/li&gt;
&lt;li&gt;bg - Resume a suspended job in the background.&lt;/li&gt;
&lt;li&gt;fg - Bring a job to the foreground.&lt;/li&gt;
&lt;li&gt;jobs - List active jobs.&lt;/li&gt;
&lt;li&gt;nohup - Run a command immune to hangups.&lt;/li&gt;
&lt;li&gt;screen - Terminal multiplexer.&lt;/li&gt;
&lt;li&gt;tmux - Terminal multiplexer.&lt;/li&gt;
&lt;li&gt;ssh - OpenSSH SSH client (remote login program).&lt;/li&gt;
&lt;li&gt;scp - Secure copy (remote file copy program).&lt;/li&gt;
&lt;li&gt;rsync - Remote file and directory synchronization.&lt;/li&gt;
&lt;li&gt;wget - Non-interactive network downloader.&lt;/li&gt;
&lt;li&gt;curl - Transfer data from or to a server.&lt;/li&gt;
&lt;li&gt;ping - Send ICMP ECHO_REQUEST to network hosts.&lt;/li&gt;
&lt;li&gt;traceroute - Print the route packets take to the network host.&lt;/li&gt;
&lt;li&gt;netstat - Print network connections, routing tables, interface statistics, masquerade connections, and multicast memberships.&lt;/li&gt;
&lt;li&gt;ss - Another utility to investigate sockets.&lt;/li&gt;
&lt;li&gt;ip - Show/manipulate routing, devices, policy routing, and tunnels.&lt;/li&gt;
&lt;li&gt;ifconfig - Configure a network interface.&lt;/li&gt;
&lt;li&gt;iwconfig - Configure wireless network interfaces.&lt;/li&gt;
&lt;li&gt;nmcli - Command-line client for NetworkManager.&lt;/li&gt;
&lt;li&gt;systemctl - Examine and control the systemd system and service manager.&lt;/li&gt;
&lt;li&gt;service - Run a System V init script.&lt;/li&gt;
&lt;li&gt;init - System V-style initialization.&lt;/li&gt;
&lt;li&gt;shutdown - Halt, power-off, or reboot the machine.&lt;/li&gt;
&lt;li&gt;reboot - Reboot the system.&lt;/li&gt;
&lt;li&gt;halt - Halt the system.&lt;/li&gt;
&lt;li&gt;poweroff - Power off the system.&lt;/li&gt;
&lt;li&gt;crontab - Schedule periodic background jobs.&lt;/li&gt;
&lt;li&gt;at - Schedule commands to run at a particular time.&lt;/li&gt;
&lt;li&gt;uptime - Tell how long the system has been running.&lt;/li&gt;
&lt;li&gt;dmesg - Print or control the kernel ring buffer.&lt;/li&gt;
&lt;li&gt;uname - Print system information.&lt;/li&gt;
&lt;li&gt;lsb_release - Print distribution-specific information.&lt;/li&gt;
&lt;li&gt;hostname - Show or set the system’s host name.&lt;/li&gt;
&lt;li&gt;date - Display or set the system date and time.&lt;/li&gt;
&lt;li&gt;cal - Display a calendar.&lt;/li&gt;
&lt;li&gt;bc - An arbitrary precision calculator language.&lt;/li&gt;
&lt;li&gt;dc - An arbitrary precision calculator.&lt;/li&gt;
&lt;li&gt;dd - Convert and copy a file.&lt;/li&gt;
&lt;li&gt;tar - Archive files.&lt;/li&gt;
&lt;li&gt;gzip - Compress files.&lt;/li&gt;
&lt;li&gt;gunzip - Decompress files.&lt;/li&gt;
&lt;li&gt;bzip2 - Compress files.&lt;/li&gt;
&lt;li&gt;bunzip2 - Decompress files.&lt;/li&gt;
&lt;li&gt;zip - Package and compress files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope you find this list helpful! If you have any questions or need further details about any of these commands, feel free to ask.&lt;/p&gt;

&lt;p&gt;Yes, this was written with the following prompt to Copilot&lt;br&gt;
"Please write an article that consistents solely of 100 linux commands and what they do"&lt;/p&gt;

&lt;p&gt;#SysAdmin #DeveloperTips #LinuxTips #DevOps #CodingLife #CommandLine #LinuxTutorial #aws #linux #bash #devops&lt;/p&gt;

&lt;p&gt;Cover image from : &lt;a href="https://pixabay.com/illustrations/teacher-profession-education-5322852/" rel="noopener noreferrer"&gt;https://pixabay.com/illustrations/teacher-profession-education-5322852/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cli</category>
    </item>
    <item>
      <title>Your boss no longer accepts this idle excuse...</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Wed, 10 Jul 2024 13:15:37 +0000</pubDate>
      <link>https://forem.com/raddevus/your-boss-no-longer-accepts-this-idle-excuse-388j</link>
      <guid>https://forem.com/raddevus/your-boss-no-longer-accepts-this-idle-excuse-388j</guid>
      <description>&lt;p&gt;Just a few short months ago, it was wasy to go to your boss and say, "StackOverflow is down so I can't move forward with my project." 🙄&lt;/p&gt;

&lt;p&gt;But, she will no longer accept that answer.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4bifketfu1mr7bohfld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4bifketfu1mr7bohfld.png" alt="Copilot is up, right?" width="445" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Dev game has changed to a whole new level.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>10 Billion Passwords Cracked: Do You Even Understand Password Cracking? Do You, Really?</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Tue, 09 Jul 2024 20:13:35 +0000</pubDate>
      <link>https://forem.com/raddevus/10-billion-passwords-cracked-do-you-even-understand-password-cracking-do-you-really-37ho</link>
      <guid>https://forem.com/raddevus/10-billion-passwords-cracked-do-you-even-understand-password-cracking-do-you-really-37ho</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you understood how passwords were cracked, you'd never use a natural-language word in your password again.  And, that alone could make you entirely safe.  Yes, I'll explain how that could make you safe further along in this article.&lt;/p&gt;

&lt;p&gt;I'm taking a bit of an alternate view so we can think differently about what password cracks actually mean, and if passwords are just entirely unusable or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;All of the Security Geniuses tell you that passwords are a failed technology because so many passwords are cracked.  But, why don't they ever clearly explain how passwords are cracked?&lt;/p&gt;

&lt;p&gt;There seems to be a Movement that is trying to get rid of passwords that you own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bombastic News
&lt;/h2&gt;

&lt;p&gt;One of the problems is that the news covers low-brow technical issues in a bombastic way ("High-sounding but with little meaning". &lt;/p&gt;

&lt;p&gt;Check out this article from today on LinkedIn. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/news/story/nearly-10-billion-passwords-leaked-6091644/" rel="noopener noreferrer"&gt;Nearly 10 billion passwords leaked | LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm0gugf2zbqjywue6tw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm0gugf2zbqjywue6tw9.png" alt=" " width="619" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;10 Billion passwords!?  What?&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Rip That Article Apart Now, Shall We?
&lt;/h2&gt;

&lt;p&gt;The article states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"...almost 10 billion unique passwords have been posted to a hacking forum"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That leads you to believe that 10 Billion plaintext passwords ripe for the using have been posted.&lt;/p&gt;

&lt;p&gt;However, that cannot be true.  Because if it were, then what would the other sentences in the article mean?  Especially the last one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It could enable "brute-force attacks," which use trial and error to rapidly test a large number of passwords and gain access to systems that aren't protected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why would attackers need to do "brute-force attacks which use trial and error" when they have the passwords in the clear?  Well, that's because they don't.  &lt;/p&gt;

&lt;p&gt;It is Alarmist reporting.  I followed the links to the source article (on qz.com) and that article is even shorter and doesn't explain it at all.  So, they did not post 10 Billion plaintext passwords at all.&lt;/p&gt;

&lt;p&gt;But you already knew that Journalists do no work at all.  They just make up sentences, then other "news" sites pick up the information and repeat it and it provides it with gravitas so the truth is no longer necessary.  As long as you have shocking headlines, you win.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thing They Never Explain
&lt;/h2&gt;

&lt;p&gt;Often the news reports these kinds of numbers and they report bad passwords, right?&lt;/p&gt;

&lt;p&gt;It is obvious that many of those accounts and passwords are just for fake accounts or "pass-by" accounts where users have created a quick account to discover more information about a company or get a free item or whatever. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Point: Fake Accounts With Bad Passwords
&lt;/h2&gt;

&lt;p&gt;So, even though there are really bad passwords like (password1, abc123) what they don't explain to the reader is that there are millions of accounts created by pass-by users and others created by hackers and those users don't care about the password at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yes, Normal People Create Bad Passwords
&lt;/h2&gt;

&lt;p&gt;Yes, I know, normal people create terrible passwords.  However, there is a simple thing they can do to make their passwords safe: Never use a natural-language word in the password.  &lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Instead, create a completely random set of characters as your password.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Normal users would have no way to remember a set of random characters.  &lt;/p&gt;

&lt;p&gt;Obviously, that can be solved by forcing the user to use a Password Manager which generates random passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Weird Solution: Hamster Method
&lt;/h2&gt;

&lt;p&gt;Here's a way to make a normal user's accounts almost entirely safe.  Please chime in and comment below to argue why this might not be true. &lt;/p&gt;

&lt;p&gt;Here are the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create one random password for the user's main email account by having a hamster run across the keyboard.&lt;/li&gt;
&lt;li&gt; I just dropped my hamster on my keyboard and got : adgy788t6ops;ldfkyudt621@DCG32#@&amp;amp;&lt;/li&gt;
&lt;li&gt;Use this one for her master password on her email account.  That way her main email account is protected with a random strong password.&lt;/li&gt;
&lt;li&gt; Write this down and keep in a sealed lock box -- at some point the user will have it memorized&lt;/li&gt;
&lt;li&gt;After that, every time the user creates a new account she should drop the hamster on the keyboard again and generate a password, but for these accounts they do not need to be written down anywhere?  What?&lt;/li&gt;
&lt;li&gt; Each time the user goes to sign into any of the other accounts she will always simply say, "oh, I don't know my password, please reset the account" sent to her main email account.&lt;/li&gt;
&lt;li&gt;She will retrieve the reset from the main email account and login&lt;/li&gt;
&lt;li&gt;Now there  is only one Main password to remember / use and the other ones will all just be reset every time.  Isn't this GENIUS?!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My point is:  If No One Knows Your Password (including you), It's Secure&lt;/p&gt;

&lt;h2&gt;
  
  
  My Real Point Is : Random!
&lt;/h2&gt;

&lt;p&gt;My real point is that passwords must be random so they cannot be guessed. &lt;/p&gt;

&lt;p&gt;But, to better state that point, I'd like to say this:&lt;/p&gt;

&lt;p&gt;Passwords ust not include any pattern that someone can detect as a pattern. &lt;/p&gt;

&lt;p&gt;That's true random.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Crackers Crack Passwords
&lt;/h2&gt;

&lt;p&gt;People seem to forget how crackers actually crack the passwords.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Ignore PlainText Storage
&lt;/h2&gt;

&lt;p&gt;Let's ignore the companies which are storing your password in plaintext, ok?  Do they still exist?  I hope not. If they do then you are toast.  No getting around that.  Crackers going to crack and they going to get a password trove that is in plaintext.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate All The Hashes &amp;amp; Compare
&lt;/h2&gt;

&lt;p&gt;The real way that crackers get passwords is:&lt;/p&gt;

&lt;p&gt;Write an algorithm which hashes suspected passwords and password phrases to generate a huge database of hashes&lt;br&gt;
Compare those hashes to what they find in the trove they exfilitrate from a company.&lt;br&gt;
That's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Think About The Size of SHA256 Hash
&lt;/h2&gt;

&lt;p&gt;So, 256-bit value is the value of 2^256.&lt;/p&gt;

&lt;p&gt;The max value is :&lt;/p&gt;

&lt;p&gt;115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,935&lt;/p&gt;

&lt;p&gt;Let's refer to that number as HUGE-NUMBER.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reach In Bag, Pull One Random Item Out
&lt;/h2&gt;

&lt;p&gt;Think about this experiment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reach into a bag (without looking) which contains HUGE-NUMBER of items and randomly pull one item out.&lt;/li&gt;
&lt;li&gt;Throw the item back into the bag with the rest of HUGE-NUMBER items.&lt;/li&gt;
&lt;li&gt;Reach in a second time (without looking) and attempt to randomly pull the same one out again. Theoretically impossible!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why does this matter?
&lt;/h3&gt;

&lt;p&gt;This matters because any unique input will produce a new and unique output.  At this point there are no collisions known in the SHA256 algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does any of this matter?
&lt;/h3&gt;

&lt;p&gt;It matters, because we are going to use a SHA256 hash as our password. &lt;/p&gt;

&lt;p&gt;Why?  Because the SHA256 value is random.  It's the equivalent of having a hamster run over your keyboard and create a password.&lt;/p&gt;

&lt;h2&gt;
  
  
  But How Are SHA256 Hashes Generated?
&lt;/h2&gt;

&lt;p&gt;Well, we don't have to know how the dark details of the SHA256 algorithm work exactly, but we do need to know how to generate one.&lt;/p&gt;

&lt;p&gt;We can use libraries which contain the SHA256 algorithm to generate SHA256 hashes.&lt;/p&gt;

&lt;p&gt;Microsoft provides such a library and you can get to it via PowerShell&lt;/p&gt;

&lt;h2&gt;
  
  
  PowerShell Script to Create SHA256 From Any Text
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;param (
  [string]$target = $(Read-Host)
)
$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write($target)
$writer.Flush()
$stringAsStream.Position = 0
$outHash = Get-FileHash -InputStream $stringAsStream | Select-Object Hash
$outHash.hash.ToLower()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;First we read in a string value provided by the user ($target) at the command line.&lt;/li&gt;
&lt;li&gt;Next, we set up a StringStream and set the value to the user-supplied string ($target)&lt;/li&gt;
&lt;li&gt;Next, we call Get-FileHash (generates SHA256) and pass the user-supplied string to it&lt;/li&gt;
&lt;li&gt;Finally, we lowercase the hash just for consistency.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here are some words that I've hashed for you.  I ran this on my Ubuntu 22.04.4 system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk3xn965vh0jjpfvaq1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk3xn965vh0jjpfvaq1z.png" alt=" " width="583" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  64 Characters Long
&lt;/h2&gt;

&lt;p&gt;The hashes are 64 characters long, because each of the 32 bytes (256 bits / 8 bits = number of bytes = 32) are represented by a 2 char Hexadecimal value.&lt;/p&gt;

&lt;p&gt;Get the source (at the top this article) and you can try it too.&lt;/p&gt;

&lt;p&gt;Here's a list of random words and their SHA256 hashes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvqxe8jm8fmnm88ed1l8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvqxe8jm8fmnm88ed1l8.png" alt=" " width="620" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Suggestion Is One I Use
&lt;/h2&gt;

&lt;p&gt;My suggestion is that instead of making up a password again, you instead generate a SHA256 hash and use that as your password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Couldn't A Cracker Generate The Same Hash?
&lt;/h2&gt;

&lt;p&gt;But, wait, can't someone just use the same words I used to generate a SHA256 hash and then compare their hash to mine and then know what my password is?&lt;/p&gt;

&lt;p&gt;Well, not really.  Here's why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make Your Hash Salty
&lt;/h2&gt;

&lt;p&gt;First of all you'd need to use two pieces of data in your hash so you could create very random hashes.&lt;/p&gt;

&lt;p&gt;In order to make it more difficult (or theoretically impossible) for someone to get our original value, we need to add a 2nd value to our initial input. This 2nd value is called a salt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Salt: Additional Word Or Phrase
&lt;/h2&gt;

&lt;p&gt;For example we could create an additional word or phrase that we would append to every input that we will hash.&lt;/p&gt;

&lt;p&gt;Here's all of the previous words with their associated hashes after adding the same salt to each one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvis9wcr74t9xi3mxnwxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvis9wcr74t9xi3mxnwxz.png" alt=" " width="634" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See how different the hashes are now?  They're not guessable by any means. If they were then SHA256 hash algorithm would be cracked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep That Salt Secret
&lt;/h2&gt;

&lt;p&gt;But, you have to keep that salt secret.  If it gets out then the cracker can generate all the words in the dictionary and hash them and then brute-force compare them all to the trove of SHA256 hashes that are in the 10 Billion password vault.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Really Need Is A Program To Do This For You
&lt;/h2&gt;

&lt;p&gt;I just so happen to have written such a program and it is FOSS (Fully Open Source Software) and it is FREE forever.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can try it for FREE&lt;/li&gt;
&lt;li&gt;You can use it for FREE&lt;/li&gt;
&lt;li&gt;You can examine and alter the software all you want...for FREE&lt;/li&gt;
&lt;li&gt;Try It For Free&lt;/li&gt;
&lt;li&gt;You can try it, right now in your browser if you want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Just go to C'YaPass : &lt;a href="https://cyapass.com/" rel="noopener noreferrer"&gt;Never type a password again&lt;/a&gt; and you'll see something like the following:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0vu1llmwlzoqv8rfyuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0vu1llmwlzoqv8rfyuf.png" alt=" " width="632" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SiteKeys: Add Your Own
&lt;/h2&gt;

&lt;p&gt;Of course, you won't have any siteKeys, but you can add them.  &lt;/p&gt;

&lt;p&gt;There are two parts to generating your password.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The SiteKey - unique string you make up to remember which site you'll use this pwd on.&lt;/li&gt;
&lt;li&gt;A pattern you draw which generates a value - this is the salt to randomize the SHA256 hash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, the value in at the lower right of the screen is a 64 character password (SHA256 hash) you can use on the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Passwords Aren't Stored Anywhere, They're Generated Every Time
&lt;/h2&gt;

&lt;p&gt;This is cutting edge technology because your passwords are never stored anywhere.&lt;/p&gt;

&lt;p&gt;To generate your password, you have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select your SiteKey&lt;/li&gt;
&lt;li&gt;Draw your pattern&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  You Only Need One Pattern
&lt;/h2&gt;

&lt;p&gt;Because the pattern is the salt, each time you change your sitekey (select a different one on the left side) you will get a new password for the associated site.  So you don't have to change the pattern for every sitekey.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Your Passwords Will Not Be Based On Natural-Language Words
&lt;/h2&gt;

&lt;p&gt;This means your passwords will be random numbers and characters. They will not be in cracker's rainbow tables as targets to match.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Sites Will Hash Your Hash
&lt;/h2&gt;

&lt;p&gt;When you use these hashes as your password, the sites you log into will then hash it to save it on their site which is interesting too.&lt;/p&gt;

&lt;p&gt;But, I've added another layer of protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Hash: Hash Your Hash Numerous Times
&lt;/h2&gt;

&lt;p&gt;Take a look at the updated C'YaPass and you'll see I've added the ability for you to hash the initial value X number of times (selectable by you).  See the red highlighted section.  If you change that value, then all of your hashes will be hashed X (10 in the example) extra times.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy59x7979xrgetr1n042v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy59x7979xrgetr1n042v.png" alt=" " width="674" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;If you wanted really strong passwords, you would never use natural-language words in your passwords. EVER!&lt;/li&gt;
&lt;li&gt;It seems that Password Problems are being reported on improperly to gain attention and to scare people for some reason.  Passwords are fine and you own them yourself.  But, they should never include words from natural-language.  NEVER!&lt;/li&gt;
&lt;li&gt;The reported password breach of 10 Billion passwords is obviously reported improperly.  Those are not plaintext passwords but instead are (most likely) hashes of passwords which, if they include natural-language words the crackers may be able to use after brute-forcing their algorithm to generate SHA256 hash matches.  That's the real password cracking technology today: hash matching.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Hash Matching
&lt;/h2&gt;

&lt;p&gt;Since hash matching is the real way crackers are cracking passwords then it means you understand better what crackers are doing.  Since you understand it better, you undersand you NEVER want to have natural-language words in your passwords.  &lt;/p&gt;

&lt;p&gt;To protect yourself, use a password generator which generates random passwords.&lt;/p&gt;

&lt;p&gt;If you liked this article, check out my github sources for C'YaPass:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/raddevus/CYaPass-Web" rel="noopener noreferrer"&gt;Web based solution&lt;/a&gt; - (also seen at &lt;a href="https://cyapass.com/" rel="noopener noreferrer"&gt;https://cyapass.com/&lt;/a&gt;) &lt;br&gt;
&lt;a href="https://github.com/raddevus/CYaPass-Electron" rel="noopener noreferrer"&gt;ElectronJS&lt;/a&gt; (cross-platform solution) - runs on macOs, Windows, Linux&lt;/p&gt;

&lt;p&gt;And don't believe everything you read about passwords.  🤓&lt;/p&gt;

</description>
    </item>
    <item>
      <title>.NET Core WebAPI (Auto)Binding Parameters When Calling Via JavaScript Fetch</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Fri, 14 Jun 2024 15:27:13 +0000</pubDate>
      <link>https://forem.com/raddevus/net-core-webapi-autobinding-parameters-when-calling-via-javascript-fetch-31e4</link>
      <guid>https://forem.com/raddevus/net-core-webapi-autobinding-parameters-when-calling-via-javascript-fetch-31e4</guid>
      <description>&lt;h2&gt;
  
  
  Get the Source Code For This Article
&lt;/h2&gt;

&lt;p&gt;All of the source code for this article is &lt;a href="https://github.com/raddevus/BindApi" rel="noopener noreferrer"&gt;located at my github repo&lt;/a&gt;. It's all C# .NET Core 8.x and JavaScript code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is a fast article with multiple examples of how to leverage the user of .NET Core WebAPI Auto-Binding feature.  I know this is often called Model Binding, but my examples cover the case where you are just passing in one parameter value to a WebAPI method.&lt;/p&gt;

&lt;p&gt;I also wrote this up at my blog in a slightly less refined article so you can check there for more details &amp;amp; to post comments if you like: &lt;a href="https://buildip.dev/?p=88" rel="noopener noreferrer"&gt;JavaScript Fetch With .NET Core WebAPI: Fetch Method Examples For Auto Binding – Build In Public Developer&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How This Article Will Work
&lt;/h2&gt;

&lt;p&gt;I will provide two things for every example so you can see exactly how the Auto-Binding feature works in .NET Core WebAPI.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebAPI method definitions (sample code via minimal API)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;JavaScript Fetch examples you can use to POST to the WebAPI &amp;amp; see the result
WebAPI Parameter Attributes&lt;/li&gt;
&lt;li&gt;.NET Core WebAPI methods allow you to mark parameters with a numnber of different attributes:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;[FromQuery]&lt;/li&gt;
&lt;li&gt;[FromForm]&lt;/li&gt;
&lt;li&gt;[FromBody]&lt;/li&gt;
&lt;li&gt;[FromHeader]&lt;/li&gt;
&lt;li&gt;[FromServices]*&lt;/li&gt;
&lt;li&gt;[FromKeyedServices]*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*The last two are brand new to .NET Core 8.x &amp;amp; I will not cover them here.  However, I will cover the first four Attributes with full examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;While writing another article where every user gets their own database (coming soon) I hit an issue with Auto-Binding parameters in .NET Core WebAPIs.   &lt;/p&gt;

&lt;p&gt;I have written a number of .NET Core WebAPIs but I've noticed that at times it has been easier than others.  I generally like my WebAPIs to use [FromBody] to get the data from the posted body. &lt;/p&gt;

&lt;p&gt;However, I discovered the exact reason why this would fail for me in certain situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FromQuery On the WebAPI Parameter
&lt;/h2&gt;

&lt;p&gt;Let's start out with what I consider the simplest method of posting data, using the [FromQuery] attribute on the WebAPI method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;I'll add the shortest amount of code here that makes it possible to create a quick discussion but if you want to see the source code you can download it from the top of this article or get it at my GitHub repo.&lt;/p&gt;

&lt;p&gt;I'll create very small project of minimal WebAPIs and the methods will be named the same in almost every case, except they will include a number for each example so you can fired up the WebAPI locally and try the examples yourself if you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start WebAPI: Use Browser To Test
&lt;/h2&gt;

&lt;p&gt;Once you start the WebAPI (from the downloaded code) you can load the URL and use your browser console to use JavaScript Fetch API to POST to the WebAPI.  Here's snapshot of what that looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tyiq44mfwo2trju8o2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tyiq44mfwo2trju8o2w.png" alt="Web API - Fetch JS from browser console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [FromQuery] Sample Code
&lt;/h2&gt;

&lt;p&gt;C#&lt;br&gt;
&lt;code&gt;[HttpPost] public ActionResult RegisterUser1([FromQuery] string uuid)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In our Minimal API you will see this method defined in the following way:&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser1", IResult ([FromQuery] string uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"QUERY - You sent in uuid: {uuid}" });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  JavaScript Fetch For [FromQuery]
&lt;/h2&gt;

&lt;p&gt;JavaScript&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser1?uuid=987-fake-uuid-1234`,
      {method: 'POST'})
        .then(response =&amp;gt; response.json())
        .then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That one is easy enough.  If you provide the &lt;code&gt;queryString&lt;/code&gt; item (?uuid) in the URL then the item will be auto-bound to the uuid string variable and you'll get a valid result back. However, if you don't provide the &lt;code&gt;queryString&lt;/code&gt; value, then an error will occur in the WebAPI when it attempts to auto-bind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error
&lt;/h3&gt;

&lt;p&gt;An unhandled exception has occurred while executing the request.&lt;br&gt;
      Microsoft.AspNetCore.Http.BadHttpRequestException: &lt;br&gt;
Required parameter "string uuid" was not provided from query string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FromForm On the WebAPI Parameter
&lt;/h2&gt;

&lt;p&gt;Let's define our second WebAPI method using the [FromForm] attribute.&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser2", IResult ([FromForm] string uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  NOTE - AntiForgery
&lt;/h3&gt;

&lt;p&gt;As soon as I started running Fetch against the command above, I started getting an odd error message on the WebAPI side which looked like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Unhandled exception. System.InvalidOperationException: Unable to find the required&lt;br&gt;
 services. Please add all the required services by calling &lt;br&gt;
'IServiceCollection.AddAntiforgery' in the application startup code.&lt;br&gt;
   at Microsoft.AspNetCore.Builder&lt;br&gt;
.AntiforgeryApplicationBuilderExtensions&lt;br&gt;
.VerifyAntiforgeryServicesAreRegistered(IApplicationBuilder builder)&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Breaking Change To .NET Core Minimal WebAPIs
&lt;/h2&gt;

&lt;p&gt;Luckily I was able to search and discover what the problem is and how to fix it.  Sheesh!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/8.0/antiforgery-checks" rel="noopener noreferrer"&gt;Breaking change: IFormFile parameters require anti-forgery checks - .NET | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Slightly Changed WebAPI for FromForm
&lt;/h2&gt;

&lt;p&gt;C#&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser2", IResult ([FromForm] string uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})
.DisableAntiforgery()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sheesh!  It's always something!&lt;/p&gt;

&lt;h2&gt;
  
  
  JS Fetch Call For FromForm
&lt;/h2&gt;

&lt;p&gt;There's some setup to pass our data on a web form.  First we have to create the FormData object and add our name/value pairs.  After that we can post the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 1. Create the FormData object
var fd = new FormData();
// 2. Append the name/value pair(s) for values you want to send
fd.append("uuid", "123-test2-2345-uuid-551");
fetch(`http://localhost:5247/RegisterUser2`,{
      method:'POST',
     body:fd,   // add the FormData object to the body data which will be posted
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now that we've used two different attributes that have worked well.  Let's delve into using [FromBody] attribute which will present great difficulty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FromBody On the WebAPI Parameter
&lt;/h2&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser3", IResult ([FromBody] string uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"FORM - You sent in uuid: {uuid}" });
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  JavaScript Fetch Call for FromBody Is Problematic
&lt;/h2&gt;

&lt;p&gt;At first look, this one should be easy, because you may think you should just be able to pass in a string value on the body.  That's what I thought, anyways.&lt;/p&gt;
&lt;h2&gt;
  
  
  Doesn't Work
&lt;/h2&gt;

&lt;p&gt;JavaScript&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:"yaka-yaka",   
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, that won't even make it past your browser, because it expects you to define an object (between two { } curly braces) for the body.&lt;/p&gt;

&lt;p&gt;Next, you may believe you can just create an object which includes the name of the target param (uuid) and pass that, something like the following:&lt;/p&gt;

&lt;h2&gt;
  
  
  Doesn't Work 2
&lt;/h2&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var data = {"uuid":"yaka-yaka"};
fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:data,   
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That doesn't work and won't get past your browser either.  Again, it believes the body object is constructed improperly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doesn't Work 3
&lt;/h2&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:{"uuid":"this-is-uuid-123"},   
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Still doesn't work.  you will get a &lt;code&gt;415 Unsupported Media type&lt;/code&gt;.  So you need to add the Content-Type object and set it to JSON so the Fetch call knows you intend to make the call with JSON.  That has happened because you added the curly brackets to the body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doesn't Work 4: But Does Hit WebAPI
&lt;/h2&gt;

&lt;p&gt;This one does actually hit the WebAPI.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser3`,{
      method:'POST',
     body:{"uuid":"this-is-uuid-123"},   
    headers: {
           'Content-type':'application/json; charset=UTF-8',
       },
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, now you get the error from the Server which states:&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Bind Error: WebAPI Couldn't Bind to Variable
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to read parameter &lt;br&gt;
"string uuid" from the request body as JSON.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is an auto-bind error, because the WebAPI didn't see the uuid value, even though we did pass it in with our body object.&lt;/p&gt;

&lt;p&gt;At this point I was flabbergasted.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's The Issue:  How Do You Solve It?
&lt;/h2&gt;

&lt;p&gt;Well, you can't solve it on the JavaScript side.  Come to find out, you cannot pass a string value directly to the WebAPI as a parameter.  Instead you have to create a server-side object  that matches the client-side object.    &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating The Server-Side Object
&lt;/h2&gt;

&lt;p&gt;Here's the new class we'll add to our Program.cs (just for sample purposes):&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;record UuidHolder{
    public string uuid{get;set;}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Define RegisterUser4 For Working Example&lt;br&gt;
We will use the following WebAPI for our working example:&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser4", IResult ([FromBody] UuidHolder uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"BODY - You sent in uuid: {uuid.uuid}" });
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will keep the RegisterUser3 WebAPI method so you can see that it is impossible to get it to bind.&lt;/p&gt;

&lt;p&gt;Now, we have to slightly alter our JavaScript Fetch call to also use JSON.stringify() and then everything will work.&lt;/p&gt;

&lt;h2&gt;
  
  
  JS Fetch For FromBody &amp;amp; Using JSON.Stringify
&lt;/h2&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser4`,{
      method:'POST',
     body:JSON.stringify({"uuid":"this-is-uuid-123"}),   
    headers: {
           'Content-type':'application/json; charset=UTF-8',
       },
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;p&gt;I thought that sending the data in on the body would've been the easiest way, but it is the most difficult.  Let's cover the last one (FromHeader) and wrap this up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FromHeader On the WebAPI Parameter
&lt;/h2&gt;

&lt;p&gt;Here's the last one which allows us to put our data in the header and post it.&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapPost("/RegisterUser5", IResult ([FromHeader] string uuid) =&amp;gt;   {
    return Results.Ok(new { Message = $"HEADER - You sent in uuid: {uuid}" });
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  JavaScript Fetch For [FromHeader]
&lt;/h2&gt;

&lt;p&gt;This one is very easy to do, but I'm not entirely sure why we'd post data using headers.&lt;/p&gt;

&lt;p&gt;However, it does help us auto-bind data to some header value we may have.&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`http://localhost:5247/RegisterUser5`,{
      method:'POST', 
    headers: {
           'Content-type':'application/json; charset=UTF-8',
            "uuid":"123-456-789"
       },
})
.then(response =&amp;gt; response.json())
.then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, you can auto-bind in .NET Core WebAPI methods using any of the basic attributes and your data will get through.  When it doesn't, you'll understand where to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Material OpenApi Documentation
&lt;/h2&gt;

&lt;p&gt;Wow! I just discovered (after publishing my article) that I actually got some free documentation of my APIs via OpenApi.  &lt;/p&gt;

&lt;p&gt;The dotnet project template added a few lines in the Program.cs file which handles generating documentation.&lt;/p&gt;

&lt;p&gt;C#&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseSwagger();
app.UseSwaggerUI();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, on each post method I had added the following call:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.WithOpenApi();&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You View OpenApi Documentation?
&lt;/h2&gt;

&lt;p&gt;I searched all over the web and scanned this lengthy document that explains OpenApi documentation but it never showed me how to view the docs.  It's crazy!  I finally found out how to view the autogenerated docs here.&lt;/p&gt;

&lt;p&gt;To examine the documents start up the webapi and go to : &lt;code&gt;http://localhost:5247/swagger&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will see the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyi132a8ekysjkl1r9i6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyi132a8ekysjkl1r9i6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You Can Also Try Out The Api Via Curl
&lt;/h2&gt;

&lt;p&gt;The document is active and you can now try out the API via the UI.  It uses curl in the background to post to the webapi and you're going to see that curl can post properly to the body method.  However, it fails on the FromForm one.  Really interesting.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>So Long Again, Wayland, You Were Almost There</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Tue, 11 Jun 2024 19:05:57 +0000</pubDate>
      <link>https://forem.com/raddevus/so-long-again-wayland-you-were-almost-there-2kkd</link>
      <guid>https://forem.com/raddevus/so-long-again-wayland-you-were-almost-there-2kkd</guid>
      <description>&lt;p&gt;Originally published at my blog: &lt;a href="https://buildip.dev/?p=97"&gt;So Long Again, Wayland, You Were Almost There&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I’m running Ubuntu 22.04.4 LTS on my main desktop machine.&lt;/p&gt;

&lt;p&gt;I switched from Windows 10 (after 28 years of using Windows exclusively) and I’m quite happy on Ubuntu.&lt;/p&gt;

&lt;p&gt;I use my Ubuntu machine to :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Remote into Win10 work machines&lt;/strong&gt; (I use Remmina (Remmina remote desktop client – Remmina[^]) &amp;amp; it is far better than Windows RDP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run VirtualBox&lt;/strong&gt; which hosts my Win10 machine for rare instances when I need to do something Windows-based&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Bug That Drove Me Crazy: Stutter-typing
&lt;/h2&gt;

&lt;p&gt;A few months ago a bug arose in an uknown-to-me package named Mutter which caused the Linux terminal to stutter when you’re typing.   &lt;/p&gt;

&lt;p&gt;At times, because I type so fast, the terminal would drop letters and I’d have to back up and retype my command.  Oh it was agonizing — and it was subtle because I kept thinking, “maybe it is fixed…can’t tell…” then the stuttering!! Oy!&lt;/p&gt;

&lt;p&gt;Special Set Of Hardware &amp;amp; Software Causes the Problem&lt;br&gt;
A user had to be running Ubuntu 22.04 and have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mutter: 46.0&lt;/li&gt;
&lt;li&gt;Present in XOrg (aka X11): Yes&lt;/li&gt;
&lt;li&gt;Graphics: NVIDIA 550.67&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have an NVIDIA 1660 installed on my machine and I was still on X11.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suggested Fixes
&lt;/h2&gt;

&lt;p&gt;The suggested fixes were not great and one of them was ridiculous.  The ridiculous one was “update to Ubuntu 24.04” which is kind of a major change.  I was against it so I suffered through.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Noticed Wayland
&lt;/h2&gt;

&lt;p&gt;But, then, on Jun 07, 2024 I finally had enough because the terminal slowness was just driving me crazy.&lt;/p&gt;

&lt;p&gt;I read over the solution posted at AskUbuntu (&lt;a href="https://askubuntu.com/questions/1509058/input-delay-on-terminal-ubuntu-22-04-4/1516935#1516935)%5Bhttps://askubuntu.com/questions/1509058/input-delay-on-terminal-ubuntu-22-04-4/1516935#1516935%5D"&gt;https://askubuntu.com/questions/1509058/input-delay-on-terminal-ubuntu-22-04-4/1516935#1516935)[https://askubuntu.com/questions/1509058/input-delay-on-terminal-ubuntu-22-04-4/1516935#1516935]&lt;/a&gt; and I noticed that it said:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Present in XOrg: Yes&lt;/li&gt;
&lt;li&gt;Present in Wayland: No&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;“Ok, that sinks it”, I thought.  “I’m moving to Wayland.”&lt;/p&gt;

&lt;p&gt;Let’s Move To Wayland&lt;br&gt;
But, you may ask, why weren’t you already on Wayland?&lt;/p&gt;

&lt;p&gt;That’s a great question.  It’s becuase when I upgraded to Ubuntu 22.04 and tried Wayland I had two major issues:&lt;/p&gt;

&lt;p&gt;When connecting to remote Win10 boxes using Remmina I couldn’t ALT-TAB through processes (Why doesn’t Remmina handle sending Alt-Tab to remote computer on 22.04 Jammy Jellyfish?)&lt;br&gt;
The Android emulator wouldn’t start under Wayland (Why won’t my Android emulator start on Ubuntu 22.04?)&lt;br&gt;
So I figured I’d switch over to Wayland and try those two things and if they worked I’d stay on Wayland.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tried It &amp;amp; Both Were Resolved
&lt;/h2&gt;

&lt;p&gt;I switched over to Wayland  — the new system makes it very easy to do so — both of those issues were resolved.&lt;/p&gt;

&lt;p&gt;“That’s great”, I thought.  “I guess I’m a Wayland user now.”  But, unfortunately, it was too fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Left Wayland Again
&lt;/h2&gt;

&lt;p&gt;Today, I needed to share my screen in MS Teams but when I went to the area where the functionality should be in my Linux MS Teams installation, I could not find the Share Screen functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  MS Teams: No Share Screen Functionality
&lt;/h2&gt;

&lt;p&gt;I couldn’t figure it out at first and then it dawned on me, “I wonder if this is because of Wayland!?!”&lt;/p&gt;

&lt;p&gt;NOTE: This is the MS Teams Linux installation (a .deb pkg) which Microsoft has basically hidden now.  But you can still get it at: (&lt;a href="https://mirror.slackware.hr/sources/teams/teams_1.5.00.23861_amd64.deb)%5Bhttps://mirror.slackware.hr/sources/teams/teams_1.5.00.23861_amd64.deb%5D"&gt;https://mirror.slackware.hr/sources/teams/teams_1.5.00.23861_amd64.deb)[https://mirror.slackware.hr/sources/teams/teams_1.5.00.23861_amd64.deb]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I logged out, hit the gear icon and started Ubuntu 22.04.4 without Wayland (running X11 again).&lt;/p&gt;

&lt;p&gt;I started up MS Teams and started a call with one of my Team members and discovered that I do have the Share Screen functionality again.&lt;/p&gt;

&lt;p&gt;This may very well be a bug in MS Teams, however, I need that functionality so I’ll be running X11 until it is resolved.&lt;/p&gt;

&lt;p&gt;I was happy to finally be on Wayland, but unfortuantely it wasn’t meant to be.  X11 is running great and the Mutter bug is resolved (sooooo glad) so all is good again.  Too bad I had to say bye to Wayland though.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Your Experience On Wayland or X11?
&lt;/h2&gt;

&lt;p&gt;Which one are you running: Wayland or X11?&lt;/p&gt;

&lt;h2&gt;
  
  
  What is your experience with Wayland?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Are your apps working properly?
&lt;/li&gt;
&lt;li&gt;Leave a comment and let me know.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linx</category>
      <category>wayland</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Is Dependency Injection the Missing Technique That's Holding Your Career Back?</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Mon, 12 Feb 2024 19:57:51 +0000</pubDate>
      <link>https://forem.com/raddevus/is-dependency-injection-the-missing-technique-thats-holding-your-career-back-1f2e</link>
      <guid>https://forem.com/raddevus/is-dependency-injection-the-missing-technique-thats-holding-your-career-back-1f2e</guid>
      <description>&lt;h2&gt;
  
  
  Get The Code
&lt;/h2&gt;

&lt;p&gt;As you read this article, you are going to see a lot of code snippets.  You can get the source code to the entire project and run it using .NET Core.  All source code is at my GitHub: &lt;a href="https://github.com/raddevus/InterfaceStudy"&gt;https://github.com/raddevus/InterfaceStudy&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Yes, the title of this article was an attempt to get your attention.  But, I hope you'll stay with me, because I've been learning &amp;amp; using OOP (Object Oriented Programming) for 30 years and Dependency Injection (DI) still sometimes alludes me and annoys me.  I'm very interested in what you think of DI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Injection Has Taken Over OOP?
&lt;/h2&gt;

&lt;p&gt;I understand the benefit of using DI but there are places where it feels as if it obscures the clarity of code.  At this moment in "Software Development History", it seems that Dependency Injection has taken over almost every other idea in OOP.  I want to talk about that and hopefully get feedback from you about how you feel about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  DI: Promises, Promises
&lt;/h3&gt;

&lt;p&gt;The promise of Dependency Injection (DI) is that code is more loosely coupled.&lt;br&gt;
Loosely coupled code means you should be able to switch out pieces more easily. &lt;/p&gt;

&lt;p&gt;That should mean that extending your code and changing it is easier.&lt;/p&gt;
&lt;h2&gt;
  
  
  Large Projects With DI Architecture?
&lt;/h2&gt;

&lt;p&gt;However, I don't know if you've been on any larg(er) projects where much of the architecture is based upon Dependency Injection, because they can be very odd to debug and deal with.  Especially if there is a IoC (Inversion of Control) Container involved -- the company I work for uses Microsoft Unity (see UnityContainer.org for more) -- this is not the Unity game engine.&lt;/p&gt;
&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In the past 4 - 6 years the company I work for has pushed DI to the forefront: all code that is created must use DI, there are no exceptions.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Write / Log Anywhere
&lt;/h2&gt;

&lt;p&gt;I've also often thought about a specific solution that I'd like to see which allows me to write code debugging statements to a file, to a database or even post them to a WebAPI.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Request For Comments (RFC)
&lt;/h2&gt;

&lt;p&gt;I finally created a good start the contains full implementation of my idea which is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built on full Dependency Injection concept&lt;/li&gt;
&lt;li&gt;Guides the implementor to use the code to build their implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm really hoping that you'll take a look at my design and tell me what you think. &lt;/p&gt;

&lt;p&gt;I'm hoping that if you've never really dealt with Dependency Injection it'll open your eyes and make you consider where you might use it.  &lt;/p&gt;

&lt;p&gt;But I'm also hoping that some of you will give the counterpoint (why you don't like it) also.&lt;/p&gt;

&lt;p&gt;Now, let's get started as I try to explain what I'm trying to get there and why I'm using Dependency Injection for this design.&lt;/p&gt;
&lt;h2&gt;
  
  
  It All Starts With Behaviors
&lt;/h2&gt;

&lt;p&gt;Interfaces are really just contracts of behavior.   They have no implementation, but instead are just a promise of some future behavior that will be provided by the classes.&lt;/p&gt;
&lt;h3&gt;
  
  
  What I Want
&lt;/h3&gt;

&lt;p&gt;I want a way to track the activity that is going on in my code.  I want a way to quickly and easily add a line of code which :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logs a message that I provide&lt;/li&gt;
&lt;li&gt;timestamps the message&lt;/li&gt;
&lt;li&gt;WriteActivity Method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To me, that sounds like a &lt;code&gt;WriteActivity&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I'm going to add that to an Interface and here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface ITrackable
{
    bool WriteActivity(String message);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.  The method will take a &lt;code&gt;String message&lt;/code&gt; that will be stored and it will return a &lt;code&gt;bool&lt;/code&gt; (true if successful, otherwise false).&lt;/p&gt;

&lt;h2&gt;
  
  
  Forcing the Implementor
&lt;/h2&gt;

&lt;p&gt;Now, keep in mind that this contract of &lt;code&gt;WriteActivity&lt;/code&gt; is really a way to force the implementor (developer who uses Interface) to implement this method. &lt;/p&gt;

&lt;h3&gt;
  
  
  Next Question: Where Will It Write the Message?
&lt;/h3&gt;

&lt;p&gt;We need a way to tell it to write to Storage of some kind.  In this case I'm thinking of three possible choices (there could be more in the future):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;file&lt;/strong&gt; (need a path and file name)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;database&lt;/strong&gt; (need a database and table)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebAPI&lt;/strong&gt; endpoint (need a URL)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Different Storage Types: Different Configurations
&lt;/h3&gt;

&lt;p&gt;In each case I need a different type of configuration.  &lt;/p&gt;

&lt;p&gt;Well, the first thing I'm thinking here is that I can store the file, the database connection or the URL as a string.  Okay, let's force the implementor to also implement a place to hold the string which will represent the target storage.  Plus we need a &lt;code&gt;Configure()&lt;/code&gt; call to always be called to insure that the &lt;code&gt;StorageTarget&lt;/code&gt; is set, so let's add those now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface ITrackable {

  bool WriteActivity(String message);

   // StorageTarget is one of the following:
   // 1. full-filename (including path)
   // 2. DB Connection string
   // 3. URI to location where data will be posted.

   // StorageTarget will wrap the private var 
   // used to contain the filepath,
   // connectionString, URI, etc.

   String StorageTarget { get; }
   // We need to insure that the Configure call is always made before the 
   // implementation class is instantiated.  We'll see how to force this.
   bool Configure();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  So Little, Just An Idea Really
&lt;/h2&gt;

&lt;p&gt;It's odd, because so far, it is not much of anything.  There's no implementation and barely anything here.  As a matter of fact, the new &lt;code&gt;StorageTarget&lt;/code&gt; variable is read-only and can't even be set.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Very Generic
&lt;/h2&gt;

&lt;p&gt;That's because I want the user to define a String variable name of their own to hold the &lt;code&gt;StorageTarget&lt;/code&gt;.  You see the &lt;code&gt;StorageTarget&lt;/code&gt; may be a file path or it may be a connection string to a database.  So I need this thing to be very generic.&lt;br&gt;&lt;br&gt;
Let's keep going and see if it makes any sense.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Forcing the Implementor To Initialize
&lt;/h2&gt;

&lt;p&gt;There's one more thing I want to force the implementor to do when using this design.  I want the implementor to always run a &lt;code&gt;Configure()&lt;/code&gt; method before any other code runs.&lt;/p&gt;

&lt;p&gt;I want the implementor to do this because there will be different required configuration / initialization for each of the &lt;code&gt;TargetStorage&lt;/code&gt; types.&lt;/p&gt;
&lt;h2&gt;
  
  
  Example With A File
&lt;/h2&gt;

&lt;p&gt;In the case of a file, we will need a target file path to be set so that when the &lt;code&gt;WriteActivity()&lt;/code&gt; method calls it will write to the correct (expected) file.&lt;/p&gt;

&lt;p&gt;However, it will be different for a database table.&lt;/p&gt;
&lt;h2&gt;
  
  
  Example With A Database Table
&lt;/h2&gt;

&lt;p&gt;When the &lt;code&gt;TargetStorage&lt;/code&gt; location is a database connection string then the configuration will be different.  It will consist of a connection string which points to a database and a table and sometimes other information.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In our implementation I will be using Sqlite database because you will be able to run all of the code very easily -- no special database set up like sql server or mysql.&lt;/p&gt;

&lt;p&gt;I can't force an implementor to call a method with an Interface.  However, I can do so with an abstract class.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Abstract Class: Part Virtual, Part Implementation
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public abstract class Trackable, ITrackable {

  public Trackable(){
     Configure();
  }

  // Since we are derived from ITrackable 
  // we have to "implement" 
  // the ITrackable methods, but we 
  // want the implementing class to 
  // implement them so we are going 
  // to make them abstract here.
  public abstract bool Configure();
  public abstract bool WriteActivity(String);
  public abstract String StorageTarget{get;}

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We have four methods, three abstract (unimplemented) and the other implemented (constructor):&lt;/p&gt;
&lt;h2&gt;
  
  
  Trackable() constructor calls Configure()
&lt;/h2&gt;

&lt;p&gt;The rest of the methods are the &lt;code&gt;ITrackable&lt;/code&gt; methods that we are forced to "implement" but we've made them abstract so the target implementation class will have to write those implementations.&lt;br&gt;
Now, let's finally see what an implementor will do to build on top of the &lt;code&gt;ITrackable&lt;/code&gt; and &lt;code&gt;Trackable&lt;/code&gt; classes.  After that, we can talk about whether or not it is valuable and helpful.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finally, A Realized Class: Implementation Rules!
&lt;/h2&gt;

&lt;p&gt;Let's do this in steps.  First let's just add the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class FileActivityTracker : Trackable
{

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;Trackable&lt;/code&gt; is a &lt;code&gt;ITrackable&lt;/code&gt; (via inheritance) so that means our &lt;code&gt;FileActivityTracker&lt;/code&gt; is a &lt;code&gt;ITrackable&lt;/code&gt;.  This will become important later.&lt;/p&gt;

&lt;p&gt;If you do that and then try building the program you'll get some errors from the C# compiler that look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;error CS0535: 'FileActivityTracker' &lt;strong&gt;does not implement inherited abstract member&lt;/strong&gt; '&lt;code&gt;Trackable.Configure()&lt;/code&gt;' &lt;/li&gt;
&lt;li&gt;error CS0535: 'FileActivityTracker' &lt;strong&gt;does not implement interface member&lt;/strong&gt; '&lt;code&gt;ITrackable.StorageTarget&lt;/code&gt;'&lt;/li&gt;
&lt;li&gt;error CS0535: 'FileActivityTracker' &lt;strong&gt;does not implement interface member&lt;/strong&gt; '&lt;code&gt;ITrackable.WriteActivity(string)&lt;/code&gt;'&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The compiler is warning us that we have not implemented the items which are defined in the abstract class and Interface.&lt;/p&gt;

&lt;p&gt;Let's implement the &lt;code&gt;Configure()&lt;/code&gt; method first.&lt;/p&gt;

&lt;h4&gt;
  
  
  Note: Linux or Windows
&lt;/h4&gt;

&lt;p&gt;I wrote this code so it runs on both Linux and Windows so you'll see an odd thing where I get the &lt;code&gt;Path.DirectorySeparatorChar&lt;/code&gt; for use in the path (on Windows it is backslash \ but on Linux it's slash /) but that is just overhead and not related to the true &lt;code&gt;Configure()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;In reality, you would probably just read the &lt;code&gt;FileName&lt;/code&gt; from a configuration file and that'd be it.&lt;/p&gt;

&lt;p&gt;I added some special code here so it will create a file in your &lt;code&gt;userprofile\temp&lt;/code&gt; directory. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On Windows that is \users&amp;lt;user.name&amp;gt;\temp\ &lt;/li&gt;
&lt;li&gt;On Linux that is /home//temp/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, after that line I've added a &lt;code&gt;Console.WriteLine()&lt;/code&gt; which will let us know when the Configure() method runs.  &lt;/p&gt;

&lt;p&gt;This is just for demonstration purposes, because I want you to see that the method runs before the implementation class (&lt;code&gt;FileActivityTracker&lt;/code&gt;) runs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Real Implementation, Probably Uses App.Config
&lt;/h2&gt;

&lt;p&gt;My point is that in the real implementation, the only code that would really be in the &lt;code&gt;Configure()&lt;/code&gt; method is the code to set up the &lt;code&gt;FileName&lt;/code&gt; that will be written to.  And that would probably come from some startup config (&lt;code&gt;app.config&lt;/code&gt;) that is read when the app starts.&lt;/p&gt;

&lt;p&gt;And, oh yeah, keep your finger on that &lt;code&gt;FileName&lt;/code&gt; variable because it is really a backing field to the class &lt;code&gt;TargetStorage&lt;/code&gt; Property that we need to add (below).  Hopefully, it'll make more sense in a moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public override bool Configure(){
   char pathSlash = Path.DirectorySeparatorChar;
   Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff tt")} : Configure() method called! ");

   // read values from configuration
   FileName = @$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}{pathSlash}temp{pathSlash}InterfaceStudy.log";

   return true;

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are also missing the implementation of StorageTarget so let's add that property now.&lt;/p&gt;

&lt;h2&gt;
  
  
  StorageTarget: Just A Pass-thru Property
&lt;/h2&gt;

&lt;p&gt;In an attempt to force the implementor to understand that she will need a place to store the file name, connection string etc. I've added this &lt;code&gt;StorageTarget&lt;/code&gt; thing.  However, it is really just a common variable name that we use to get to the true value that holds the value of target.&lt;/p&gt;

&lt;p&gt;The user will create a private backing field which has a more definitive name for what the &lt;code&gt;StorageTarget&lt;/code&gt; is.  In my example I name that backing field &lt;code&gt;FileName&lt;/code&gt;.  Here's the code that will be added to our &lt;code&gt;FileActivityTracker&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private overrid String FileName;

public override string StorageTarget
{
   get
   {
       return FileName;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FileName&lt;/code&gt; variable cannot be touched externally and can only be set from within the &lt;code&gt;FileActivityTracker&lt;/code&gt; class&lt;/p&gt;

&lt;p&gt;Finally, we get to see the implementation of the &lt;code&gt;WriteActivity(String message)&lt;/code&gt; method and I believe that will all make it a bit clearer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public override bool WriteActivity(String message)
{
  try
  {

    File.AppendAllText(StorageTarget, $"{DateTime.Now.ToLongTimeString()}: {message} {Environment.NewLine}");
    return true;
  }
  catch (Exception ex)
  {
    return false;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keeping It Simple
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;WriteActivity&lt;/code&gt; method is very simple.  It is just a call to &lt;code&gt;File.AppendAllText&lt;/code&gt; (part of .NET libraries) to write a line of text to a text file. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;File.AppendAllText&lt;/code&gt; takes two parameters:&lt;/p&gt;

&lt;p&gt;Full file path to the file the method will open and write to&lt;br&gt;
An output string to write to the target file&lt;br&gt;
The magic in our implementation is that the first parameter is our &lt;code&gt;StorageTarget&lt;/code&gt;.  It is our generically named String which was configured to point to our target file.&lt;/p&gt;

&lt;p&gt;The output just contains some additional information which is added to the user's message variable.   In this case we add a &lt;code&gt;DateTime&lt;/code&gt; stamp and a newline so that each time we write to the file it will be on a new line.&lt;/p&gt;
&lt;h2&gt;
  
  
  How Do We Use The Class?
&lt;/h2&gt;

&lt;p&gt;Seeing how to use the class brings it all home. &lt;/p&gt;
&lt;h3&gt;
  
  
  Hiding the Details of the Implementation
&lt;/h3&gt;

&lt;p&gt;One of the key features of seeing a simple usage is that we discover that the details of all of this implementation are hidden to the user and that is a huge benefit.  The user of the final implementation class doesn't have to think about all of this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ITrackable fat = new FileActivityTracker();
fat.WriteActivity("The app is running.");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the user needs to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;new up a &lt;code&gt;FileActivityTracker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;WriteActivity&lt;/code&gt; method to write a message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In our case with the example, the output will be stored in a file named &lt;code&gt;InterfaceStudy.log&lt;/code&gt; and the output will look like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;5:26:38 PM:   The app is running.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ITrackable: Our FileActivityTracker Is ITrackable
&lt;/h2&gt;

&lt;p&gt;It is very important to notice that our &lt;code&gt;FileActivityTracker&lt;/code&gt; is actually an &lt;code&gt;ITrackable&lt;/code&gt;.  That means we could replace this &lt;code&gt;ITrackable&lt;/code&gt; implementation with any other &lt;code&gt;ITrackable&lt;/code&gt; implementation.  We will see how this is important when we create our &lt;code&gt;SqliteActivityTracker&lt;/code&gt; and how this allows Dependency Injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Could End the Article Here
&lt;/h2&gt;

&lt;p&gt;I could stop now and you'd have a full example of designing toward the idea of Dependency Injection except we haven't exactly injected anything have we?&lt;/p&gt;

&lt;p&gt;To really understand why this technique of designing to an Interface is important we need to see how The &lt;code&gt;FileActivityTracker&lt;/code&gt; could be easily replaced by another class.  We also need to see the actual concept  of injection. &lt;/p&gt;

&lt;h2&gt;
  
  
  Constructor Injection
&lt;/h2&gt;

&lt;p&gt;What does injection mean anyways?  In our case it is going to mean injecting a particular type into a class that will use our type.  How will we inject the type?  We will send it into the class via the constructor.  This is called constructor injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Point?
&lt;/h2&gt;

&lt;p&gt;But, what is the point of all of this?  Let's say you have a class that has a method named &lt;code&gt;WriteActivity()&lt;/code&gt; -- same name as the one that we have in our Interface.  Let's say that you've implemented the &lt;code&gt;WriteActivity()&lt;/code&gt; method so it will write to a file.  Again, just as we have in our Interface.   Now, further imagine that your method is called all over the place so that users can write  messages to the file.  &lt;/p&gt;

&lt;h3&gt;
  
  
  The Change Comes &amp;amp; Destroys Your Code
&lt;/h3&gt;

&lt;p&gt;Then someone at a high level says, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We can't write files to the user's drive.  We have to store that data in a database."  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, you'd have to go in and alter the class where you've written your &lt;code&gt;WriteActivity()&lt;/code&gt; algorithm and you'd have to test all the places that call the code to make sure it works.&lt;/p&gt;

&lt;p&gt;Let's say your class and class usage looks something like the following:&lt;/p&gt;

&lt;h4&gt;
  
  
  Bad Code Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class FileWriter{
      String FileName {get;set;}
      WriteActivity(String message){
          File.AppendAllText(FileName, message);
      }

class Thing1 {
       private FileWriter fw = new FileWriter();

       Thing1(){
              fw.WriteActivity("In the Thing1 ctor...");
       }
}

class Thing2 {
       private FileWriter fw = new FileWriter();
       Thing2(){
              fw.WriteActivity("In the Thing1 ctor...");
       }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a very simple example but really take a look at it and think about it for a moment.&lt;/p&gt;

&lt;p&gt;Imagine if you change the &lt;code&gt;FileWriter WriteActivity&lt;/code&gt; method.  First of all, if you have other classes which are depending upon the class still writing to a file and you update the the method to write to a Database table then you are going to mess up all that other code.&lt;/p&gt;

&lt;p&gt;Or, as another example, imagine if the &lt;code&gt;Thing2&lt;/code&gt; class needs to write to the database but the &lt;code&gt;Thing1&lt;/code&gt; should still write to the File.  What could you do then?  Maybe create an fake overloaded method for &lt;code&gt;WriteActivity&lt;/code&gt; that looks like &lt;code&gt;WriteActivity(String message, bool useDB)&lt;/code&gt; just so you have a different method signature.  That's not great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design to An Interface: Design to Behavior
&lt;/h2&gt;

&lt;p&gt;However, if we design to behaviors and then allow just the behaviors to change we make a much easier way forward. Let's see how we might use Dependency Injection with the classes above and our &lt;code&gt;ITrackable&lt;/code&gt;, &lt;code&gt;Trackable&lt;/code&gt; solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Thing1 {

   private ITrackable fat;

   // Here's the actual Dependency Injection!
   // When we construct the Thing1 object 
   // we inject the tracker implementation 
   // which will be used later 
   Thing1(ITrackable tracker){
        fat = tracker;
    }

    int DoingWork(){

       // This code will write to a file 
       // when fat is a FileActivityTracker
       // and to Sqlite when we implement 
      //  SqliteActivityTracker.
      fat.WriteActivity("In the DoingWork() method...");
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, if we inject our &lt;code&gt;FileActivityTracker&lt;/code&gt; into &lt;code&gt;Thing1&lt;/code&gt; it will write to a file.&lt;/p&gt;

&lt;p&gt;Our calling code might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thing1 t = new Thing1(new FileActivityTracker());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can change that at any time without changing any code.  That's the value of Dependency Injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Probably Set Up In App Configuration
&lt;/h2&gt;

&lt;p&gt;And, when you really carry this out, the call to new &lt;code&gt;FileActivityTracker()&lt;/code&gt; would be set up in a app configuration so that when the app starts all of these types are set.&lt;/p&gt;

&lt;p&gt;Let's implement a &lt;code&gt;ITrackable&lt;/code&gt; that writes to Sqlite now so you can see this in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  SqliteActivityTracker Implementation Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public SqliteActivityTracker()
{

   try{
   // ########### FYI THE DB is created (if doesn't exist) when it is OPENED ########
      connection.Open();
      File.AppendAllText(@$"{rootPath}{pathSlash}{tempDir}{pathSlash}InterfaceStudy.log", $"{DateTime.Now.ToLongTimeString()}: {Environment.CurrentDirectory} {Environment.NewLine}");
      FileInfo fi = new FileInfo(@$"{rootPath}{pathSlash}{tempDir}{pathSlash}tracker.db");

      if (fi.Length == 0){
         connectionString = fi.Name;

         foreach (String tableCreate in allTableCreation){
            command.CommandText = tableCreate;
            command.ExecuteNonQuery();
        }
     }

    Console.WriteLine(connection.DataSource);

   }
   finally{
    if (connection != null){
     connection.Close();
    }
   }
}

public override bool WriteActivity(String message)
{

   Command.CommandText = @"INSERT into Task (Description)values($message);select * from task where id =(SELECT last_insert_rowid())";
   Command.Parameters.AddWithValue("$message",message);


   try{
      Console.WriteLine("Saving...");
      connection.Open();
      Console.WriteLine("Opened.");

      // id should be last id inserted into table

      var id = Convert.ToInt64(command.ExecuteScalar());

      Console.WriteLine("inserted.");

      return true;
   }

   catch(Exception ex){
     Console.WriteLine($"Error: {ex.Message}");
     return false;
   }

   finally{
      if (connection != null){
      connection.Close();
   }
 }
}

  // This creates the table for the 
  // sample project so everything is
  // done for you and all the code will run properly.
  protected String [] allTableCreation = {

      @"CREATE TABLE Task  
      ( [ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        [Description] NVARCHAR(1000) check(length(Description) &amp;lt;= 1000),
        [Created] NVARCHAR(30) default (datetime('now','localtime')) check(length(Created) &amp;lt;= 30)
      )"
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  This Is The Amazing Part: Change Without Changing Old Code
&lt;/h2&gt;

&lt;p&gt;Now that we've implemented that code, all we have to make our &lt;code&gt;Thing1&lt;/code&gt; use the &lt;code&gt;SqliteActivityTracker&lt;/code&gt; is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thing1 t = new Thing1(new SqliteActivityTracker());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all the internal (to &lt;code&gt;Thing1&lt;/code&gt;) calls to &lt;code&gt;WriteActivity&lt;/code&gt; will write to the Sqlite database instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get The Source Code and Try It
&lt;/h2&gt;

&lt;p&gt;You can get the source code and build it and try it.&lt;/p&gt;

&lt;p&gt;You will see that the only calling code is the following four lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ITrackable fat = new FileActivityTracker();
fat.WriteActivity("The app is running.");

ITrackable sat = new SqliteActivityTracker();
sat.WriteActivity("This is from the app!");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could've even made that a bit more generic to show that the same ITrackable can carry any ITrackable type by showing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ITrackable tracker = new FileActivityTracker();

// Writes to the file
tracker.WriteActivity("The app is running.");

// set tracker to carry a SqliteActivityTracker
tracker = new SqliteActivityTracker();

// writes to sqlite db
tracker.WriteActivity("This is from the app!");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dependency Injection Is Really About Design
&lt;/h2&gt;

&lt;p&gt;As you can see, DI is really about Design and thinking about your classes in a more abstract way.&lt;/p&gt;

&lt;p&gt;You have to think about shared behaviors and how you might create classes that support those similar behaviors that are implemented in different ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get The Source &amp;amp; Try It Out
&lt;/h3&gt;

&lt;p&gt;If you get the code you will see that it will write:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write to a InterfaceStudy.log file&lt;/li&gt;
&lt;li&gt;Create and write to a Sqlite db (tracker.db in same location as file)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll see output something like the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;2024-02-12 11:14:16.358 AM : Configure() method called! &lt;br&gt;
2024-02-12 11:14:16.394 AM : FileActivityTracker ctor...&lt;br&gt;
/home//temp/tracker.db&lt;br&gt;
/home//temp/tracker.db&lt;br&gt;
Saving...&lt;br&gt;
Opened.&lt;br&gt;
inserted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  New Ideas &amp;amp; Comments?
&lt;/h2&gt;

&lt;p&gt;I hope this has given you some new ideas about this concept and I hope you'll comment about what you like and don't like.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>design</category>
      <category>oop</category>
    </item>
    <item>
      <title>Software Devs: We Live In a World Of Broken Things</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Tue, 09 Jan 2024 16:40:19 +0000</pubDate>
      <link>https://forem.com/raddevus/software-devs-we-live-in-a-world-of-broken-things-2mfa</link>
      <guid>https://forem.com/raddevus/software-devs-we-live-in-a-world-of-broken-things-2mfa</guid>
      <description>&lt;p&gt;I'm building a iOS (iPhone) app which makes requests to a C# .NET Core WebAPI back-end.&lt;/p&gt;

&lt;p&gt;I'm creating the WebAPI back-end as I create the App itself.  There's a lot of back-and-forth as I change a thing in the App and then need the WebAPI to give me different data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything's Broken
&lt;/h2&gt;

&lt;p&gt;It started me thinking about how that as I work on the project, at any moment either the App or the WebAPI is broken.&lt;/p&gt;

&lt;p&gt;It gets worse really, because any time I change the WebAPI then I have a broken App and I have to fix things over there.  It's back and forth between the too and just makes a developer feel like everything is garbage.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Do Minds Deal With Broken Stuff?
&lt;/h4&gt;

&lt;p&gt;That started me thinking about my interaction creating the new software and how that actually affects me.  The thing is that no one really wants to deal with broken things and always fixing things.  Your mind will work against you as you face the software you are working on, because we want things to "just work".  &lt;/p&gt;

&lt;p&gt;It feels terrible as we confront all the broken pieces of the thing we are trying to create.  But, that's just how your mind deals with things.  It tries to run away from difficult things that are in disarray.  Brains like things to be organized and perfect, but the real world just isn't that way.  &lt;/p&gt;

&lt;p&gt;That's just a normal brain being normal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Super-Power: Being Able To Deal With Broken Things
&lt;/h3&gt;

&lt;p&gt;However, if you take a moment to assess why you feel grumpy or uncomfortable or upset as you work on the project that is in broken pieces you'll discover it is just because of wanting things to be right.&lt;/p&gt;

&lt;p&gt;Things can't get right though, unless you confront each challenge and beat it.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Break Broken Things Into Small Pieces
&lt;/h3&gt;

&lt;p&gt;My best advice (and what I'm doing in my project) each challenge into smaller things to resolve and then just work on one of them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make a list so you don't feel overwhelmed -- I've found that often when I think there are a ton of things to do it's only a few when I actually write them down&lt;/li&gt;
&lt;li&gt;Start with the smallest thing you can succeed with&lt;/li&gt;
&lt;li&gt;Turn the challenge into a Learning Experience.  Take the problem and decide that you will solve this so no one else ever has to because you will document the challenge and its resolution (this helps you get the focus off the bad feelings of things being broken and puts the focus on doing the work to resolve the issue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, I'm going to head back over to my iOS App / WebAPI and&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;work on the smallest thing I can fix&lt;/li&gt;
&lt;li&gt;look at it as a learning / documenting experience&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're stuck, break your challenges down into small pieces and examine them as if you are going to explain the solution to someone else.&lt;br&gt;
Good luck.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Password Problems (1 of 10): You Need Your Passwords On Every Device You Own</title>
      <dc:creator>raddevus</dc:creator>
      <pubDate>Fri, 06 Oct 2023 12:42:29 +0000</pubDate>
      <link>https://forem.com/raddevus/password-problems-1-of-10-you-need-your-passwords-on-every-device-you-own-2g1i</link>
      <guid>https://forem.com/raddevus/password-problems-1-of-10-you-need-your-passwords-on-every-device-you-own-2g1i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I've been working on and using C'YaPass (password generator / manager) for over 8 years now but I haven't invested a lot of time to explain how it can help make your life easier so I am writing a series of articles to do that.&lt;br&gt;
First Problem: You Need Your Passwords Everywhere&lt;/p&gt;

&lt;p&gt;I use all of the following devices on a daily basis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iPad Pro&lt;/li&gt;
&lt;li&gt;Windows 10 Laptop&lt;/li&gt;
&lt;li&gt;iPhone&lt;/li&gt;
&lt;li&gt;Linux desktop (Ubuntu 22.04.2 LTS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I need to be able to sign on from any one of these devices at any time.&lt;/p&gt;

&lt;p&gt;I’m writing this article in Google Docs on my iPad while sitting on my front porch and when I need to sign into my Google account I need my password to be available.&lt;/p&gt;

&lt;p&gt;I previously had an Android phone and needed my passwords there too.&lt;/p&gt;

&lt;h2&gt;
  
  
  C'YaPass WebApp Runs On All Devices
&lt;/h2&gt;

&lt;p&gt;C’YPass makes that possible because the Web App will run on any device. That means no matter where you go you can get to your passwords.&lt;/p&gt;

&lt;p&gt;Even if you are using a public computer or you've gone online on a friend's computer, you’ll be able to get your passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  C’YaPass Doesn’t Store You Passwords On Any Device
&lt;/h2&gt;

&lt;p&gt;However, keep in mind that C’YaPass never stores your passwords anywhere. That’s a big deal because it keeps your passwords more secure than any other system.&lt;/p&gt;

&lt;h2&gt;
  
  
  C’YaPass Generates Your Passwords
&lt;/h2&gt;

&lt;p&gt;C’YaPass uses your (required) SiteKey and (required) geometric pattern and if you choose, your Multi-Hash* value to generate a random password every time you use the system and select the SiteKey.&lt;/p&gt;

&lt;p&gt;*More about Multi-Hash in an upcoming article in this series.&lt;/p&gt;

&lt;p&gt;Since the password itself is generated every time, you never have to worry about your passwords being stolen from your system or some cloud account.&lt;/p&gt;

&lt;p&gt;It sounds impossible to reproduce the generation of a random password every time, but there is a much longer explanation of this here in my older LinkedIn article at: &lt;a href="https://www.linkedin.com/pulse/destroy-all-passwords-never-memorize-password-again-roger-deutsch/"&gt;https://www.linkedin.com/pulse/destroy-all-passwords-never-memorize-password-again-roger-deutsch/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try C'YaPass: No Installation Required
&lt;/h2&gt;

&lt;p&gt;You can try it out right now in your web browser on whatever device you're reading this article from. Here's a quick step-by-step guide to what it will look like when you try it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-By-Step Guide
&lt;/h2&gt;

&lt;p&gt;Go to the Web App on the official C'YaPass site: &lt;a href="https://cyapass.com/js/cya.htm"&gt;https://cyapass.com/js/cya.htm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll see the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jqUL8ab0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lntau3ptjig1gi3squb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jqUL8ab0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lntau3ptjig1gi3squb9.png" alt="Image description" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new SiteKey -- this is a mnemonic to remind you which site you are using this password for. It is used in conjunction with your geometric pattern (in the next step) to generate your random password. I'll Click the [Add] button and add a new SiteKey : bigBank&lt;/p&gt;

&lt;p&gt;A pop-up dialog will appear and I will set all of the Password Requirements that the site forces me to use. A Password Requirement is any one of those annoying things you have to remember when creating your password (use uppercase, include special character, password can only be a certain max length (a ridiculous requirement)). Once you filled all of those out you'll see: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xkHpsXzY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an3rfaghgszvaeyap06i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xkHpsXzY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an3rfaghgszvaeyap06i.png" alt="Image description" width="600" height="316"&gt;&lt;/a&gt;&lt;br&gt;
Creating SiteKey with password requirements&lt;/p&gt;

&lt;p&gt;Click the [OK] button and your new SiteKey will be saved with the associated Password requirements and you'll see the main page again with the new SiteKey available.&lt;/p&gt;

&lt;p&gt;Now, let's draw a pattern in the grid on the right and our randomly generated password will appear. Please note, you probably do not want to ever use the pattern I'm showing below. It the same geometric pattern I use for all my samples. Since the SiteKey and the geometric pattern are used to generate the random password, you need to keep them secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tLCQnfp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdjvarg8h6sw6r4iih55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tLCQnfp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdjvarg8h6sw6r4iih55.png" alt="Image description" width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
Password is generated &amp;amp; copied to clipboard&lt;/p&gt;

&lt;p&gt;I've highlighted two important areas (in green boxes) in the previous snapshot. The first area (on left) is showing the Password Requirements that have been set because we chose this SiteKey (bigBank) which has all three of them set. &lt;/p&gt;

&lt;p&gt;The second area (on right) is the generated password. However, you will notice that the password doesn't yet include a special character. That's because we need to type one in the Special Characters text box.&lt;/p&gt;

&lt;p&gt;C'YaPass requires that you type that special character each time you start the app for one more level of security. However, when you type that special character in there, it will use that character for any other SiteKeys that you select making less work for you to do. We'll use the special character $ (dollar sign). As soon as you type the special character in, the password will be updated to include it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--721c3SW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3a1asoof2xeeovxjegn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--721c3SW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3a1asoof2xeeovxjegn3.png" alt="Image description" width="800" height="569"&gt;&lt;/a&gt; &lt;br&gt;
   Special character is added&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a 2nd SiteKey
&lt;/h2&gt;

&lt;p&gt;Now, let's see how easy your life will be using C'YaPass when you have many more sites you need to log into (more SiteKeys) by adding a new one. Click the [Add] button again and add a new SiteKey: &lt;a href="mailto:myMail@gmail.com"&gt;myMail@gmail.com&lt;/a&gt; -- We'll make the only password requirement to use a Special Character so you can see how that works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o9PyS8E_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/py3qeo76ztadd60ei4js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o9PyS8E_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/py3qeo76ztadd60ei4js.png" alt="Image description" width="597" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As soon as you click the [OK] button to save the SiteKey A) The SiteKey will be added to your list B) the new password will be generated C) The special character will be added automatically to the password D) the password will be copied to your clipboard so you can paste it into the site where you need to login.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QLT1n9Zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8lxc8vuyigkuy23wtvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QLT1n9Zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8lxc8vuyigkuy23wtvw.png" alt="Image description" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;64 character password is generated with special character&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Take note of a couple of things. First of all the 64 character password is generated and since this SiteKey includes a special character and you've already typed it into the text box it is automatically included in the generated password. The app also copies your password to your system clipboard so you can easily paste it into the your site to login. However, some web browsers (especially on iPhones) don't always run the copy to clipboard command properly. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's where the green highlighted button to the left comes in: it is the &lt;strong&gt;copy-to-clipboard&lt;/strong&gt; button. If the password isn't copied automatically just click the button and it'll be copied.&lt;/p&gt;

&lt;p&gt;Now you know the basics of using C'YaPass.&lt;/p&gt;

&lt;h2&gt;
  
  
  SiteKeys Are Never Transferred Anywhere
&lt;/h2&gt;

&lt;p&gt;The SiteKeys you create in your browser will only be available on that particular browser on that particular device. They are never transferred anywhere. You own your SiteKeys and you decide where you will use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Destroying The SiteKeys
&lt;/h2&gt;

&lt;p&gt;As a matter of fact, you can destroy all the SiteKeys you created in our practice session above by simply clicking the [Remove All SiteKeys] button.&lt;/p&gt;

&lt;p&gt;When you click the [Remove All SiteKeys] button you will have a chance to [Cancel] the operation. A dialog box will popup and warn you. If you want to keep the SiteKeys, just click the [Cancel] button. If you do want to destroy them, click the [OK] button and they will be permanently deleted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: There is no way to get them back after you destroy them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zt3ghsT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40sti5q2j21z7uzv0c3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zt3ghsT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40sti5q2j21z7uzv0c3v.png" alt="Image description" width="595" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Popup dialog allows you to cancel removing all SiteKeys&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Get Your SiteKeys On All Devices?
&lt;/h2&gt;

&lt;p&gt;But, if the SiteKeys (along with your geometric pattern) are required to generate all of your passwords then how can we get them onto all your other devices?&lt;/p&gt;

&lt;h2&gt;
  
  
  Answer: Export &amp;amp; Import
&lt;/h2&gt;

&lt;p&gt;That's where the Export &amp;amp; Import SiteKey functionality comes in. But that is for another article in the series.&lt;/p&gt;

&lt;p&gt;If you're really interested in how that works you can read a previous article I wrote up on the CodeProject.com web site at: &lt;a href="https://www.codeproject.com/Articles/5338047/C-YaPass-The-Best-Password-Manager-You-ve-Never-Us"&gt;https://www.codeproject.com/Articles/5338047/C-YaPass-The-Best-Password-Manager-You-ve-Never-Us&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading my article and checking out C'YaPass.&lt;/p&gt;

&lt;h2&gt;
  
  
  More To Discuss: Future Articles
&lt;/h2&gt;

&lt;p&gt;There's a lot more to discuss so here's a list of topics for upcoming articles (one released every day):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting the desktop app (Can be installed on all major Operating Systems (MacOS, Linux, Windows 10/11)&lt;/li&gt;
&lt;li&gt;Getting the Android app&lt;/li&gt;
&lt;li&gt;Typing Strong Passwords Using Your Thumbs Is Terrible (Making Mobile easier)&lt;/li&gt;
&lt;li&gt;Switching To A Password Manager Is A Pain (But It Doesn't Have To Be)&lt;/li&gt;
&lt;li&gt;Passwords Are Difficult To Share (But It Doesn't Have To Be)&lt;/li&gt;
&lt;li&gt;Web Sites Have Stupid Password Requirements&lt;/li&gt;
&lt;li&gt;There Are Too Many Things to Sign Into &amp;amp; Too Many Passwords &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting The App Now: Spoiler Alert
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Windows App Store
&lt;/h4&gt;

&lt;p&gt;You can install the Windows app from the Windows App Store: &lt;a href="https://apps.microsoft.com/store/detail/cyapass/9PFD82D1Z7RW?hl=en-us&amp;amp;gl=us"&gt;https://apps.microsoft.com/store/detail/cyapass/9PFD82D1Z7RW?hl=en-us&amp;amp;gl=us&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Google Play
&lt;/h4&gt;

&lt;p&gt;You can install the Android app from Google Play: &lt;a href="https://play.google.com/store/apps/details?id=app.actionmobile.cyapass"&gt;https://play.google.com/store/apps/details?id=app.actionmobile.cyapass&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Linux Snapcraft
&lt;/h4&gt;

&lt;p&gt;You can even install the desktop app directly to your Linux distro from Snapcraft:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snapcraft.io/cyapass"&gt;https://snapcraft.io/cyapass&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  MacOS Installation
&lt;/h4&gt;

&lt;p&gt;I'll update the official site (&lt;a href="https://cyapass.com"&gt;https://cyapass.com&lt;/a&gt;) with the MacOS DMG (installation file) very soon.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
