Welcome to my homepage!
      email at this domain
      yancy at irc.libera.chat
    

This site is Lynx (web browser) friendly (mostly).



---
20240501
How to get to Newark Airport on public transit

---
20240416
The Proper Way of Adding a Cron Job

---
20240305
The Hunt for the Missing Data Type

--- ---
20240305
The Hunt for the Missing Data Type

---
20240216
Vim Color Schemes: How to Change and Use Them
---
20240216
Effectively Using Iterators In Rust
---
20240924
      Upgrade base OS:
        freebsd-update fetch
        freebsd-update install

      Check available kernel:
        freebsd-version -k

      Check running kernel:
        uname -r

      Upgrade binaries:
        pkg update

      Check for binary vulnerabilities:
        pkg audit -F
      

---
20240124
the man who carried computer science on his shoulders
---
20240115
Use GPG Keys to Send Encrypted Messages
How do I encrypt plaintext with GnuPG?
Encrypting and decrypting documents

---
20240114
        -----BEGIN PGP PUBLIC KEY BLOCK-----

        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
        gspZr68=
        =YIfr
        -----END PGP PUBLIC KEY BLOCK-----
      

---
20240112
Formatting USB drive with ext4 on FreeBSD.
        444  sudo pkg install e2fsprogs-core
        445  gpart show
        447  sudo gpart destroy -F da1
        448  sudo gpart create -s GPT da1
        449  sudo mke2fs -L tirana_storage -F -E discard -t ext4 /dev/da1
        451  sudo mount -t ext2fs /dev/da1 /mnt
      
Note to self, ext4 is super slow on FreeBSD compared to UFS. I wish I could get UFS to copy on linux.

---
20240101
Happy New Year!

---
20240101
         echo "~/mutt/muttrc"
        # About Me
        set from = "redacted-email-address"
        set realname = "Yancy"

        # My credentials
        set smtp_url = "smtp://redacted-email-address@mail.redacted-mail-server-name.net:587/"
        set smtp_pass = "redacted-password"
        set imap_user = "redacted-email-address"
        set imap_pass = "redacted-password"

        # My mailboxes
        set folder = "imaps://mail.redacted-mail-server-name.net:993"
        set spoolfile = "+INBOX"

        # Where to put the stuff
        set header_cache = "~/.mutt/cache/headers"
        set message_cachedir = "~/.mutt/cache/bodies"
        set certificate_file = "~/.mutt/certificates"

        # Etc
        set mail_check = 30
        set move = no
        set imap_keepalive = 900
        set sort = threads
        set editor = "vim"

        # Shortcut for checking on new messages
        bind index G imap-fetch-mail
        set sort_aux = last-date-received
      
---
20231201
        56.
        Those who know do not talk.
        Those who talk do not know.

        Keep your mouth closed.
        Guard your senses.
        Temper your sharpness.
        Simplify your problems.
        Mask your brightness.
        Be at one with the dust of the Earth.
        This is the primal union.

        He who has achieved this state is unconcerned with friends and enemies,
        with good and harm,
        with honor and disgrace.
        This therefore is the highest state of man.
      
---
20231130
        63.
        Practice non-action.
        Work without doing.
        Taste the tasteless.
        Magnify the small, increase the few.
        Reward bitterness with care.

        See simplicity in the complicated.
        Achieve greatness in little things.

        In the universe the difficult things are done as if they are easy.
        In the universe great acts are made up of small deeds.
        The sage does not attempt anything very big, and thus achieved greatness.

        Easy promises make for little trust.
        Taking things lightly results in great difficulty.
        Because the sage always confronts difficulties, he never experiences them.
      
---
20231130
         echo "~/.tmux.conf"
        # depends on apm for the battery status and ifconfig to fetch the current ip addr.
        set -g status-right "#(ifconfig | grep wlan0 -A 2 | grep inet | awk '{print $2}') | #(apm | grep 'Remaining battery life' | awk '{print $4}') %| %a %h-%d"
        run '~/.tmux/plugins/tpm/tpm'
      
---
20231120
        64.
        Peace is easily maintained; Trouble is easily overcome before it starts.
        The brittle is easily shattered; The small is easily scattered.

        Deal with things before they happen.
        Put things in order before there is confusion.

        A tree as great as a man's embrace springs from a small shoot;
        A terrace nine stories high begins with a pile of earth;
        A journey of a thousand miles starts under one's foot.

        Those who act defeat their own purpose;
        Those who grasp lose.
        The wise do not act and so are not defeated.
        They do not grasp and therefore do not lose.

        People usually fail when they are on the verge of success.
        So give as much care to the end as to the beginning; Then there will be no failure.

        Therefore the wise seek freedom from desire.
        They do not collect precious things.
        They learn not to hold onto ideas.
        They bring people back to what they have lost.
        They help the ten thousand things find their own nature, yet they refrain from action.
      
---
20231120
I like RSS as a standard because it is:

---
20231118
Rogue superintelligence and merging with machines: Inside the mind of OpenAI's chief scientist

---
20231118
Effective Rust
"This leads to the same kind of advice that turns up for other OO-influenced languages2: prefer accepting trait types to concrete types if future flexibility is anticipated."
"Use marker traits to distinguish behaviours that cannot be expressed in the trait method signatures."
".. check happens at compile-time, when the generic is monomorphized (Rust's term for what C++ would call "template instantiation")."

---
20231116

After watching Lecture 1A of SICP, I wrote the recursive algorithm for finding the square root of a number in Rust. The algorithem implements Heron's method , named after the Greek mathematician Hero of Alexandria (what a name, right?). Although, the method was known prior to Hero. See: babylonian mathematics 1800 - 1600 BC.

        const S: f32 = 2.0;

        fn good_enough(guess: f32, x: f32) -> bool {
            (guess * guess - x).abs() < 0.0001
        }

        fn improve(guess: f32, x: f32) -> f32 {
             //average guess and x / guess.
            (guess + x / guess) / 2.0
        }

        fn try(guess: f32, x: f32) -> f32 {
            if good_enough(guess, x) {
                guess
            } else {
                try(improve(guess, x), x)
            }
        }

        fn square_root(x: f32) -> f32 {
            try(1.0, x)
        }

        fn main() {
            let square_root = square_root(S);
            println!("square root: {}", square_root);
        }
      
Recursive representation:
        x(0) ~ sqrt(S)
        x(n + 1) = 1 /2 ( x(n) + S/x(n) ) 
      
---
20231115

I finished ex1-16 yesterday. To this point, malloc and heap allocation hasn't been described, although I don't think it would be worthwhile to try to store the contents on the stack, so I used malloc and remalloc.

          /* Excercise 1-16
         *
         * Revise the main routine of the longest-line program so
         * it will correctly print the length of arbitrary long
         * input lines, and as much as possible of the text.
         */

        #include 

        #define MAXLINE 1000 /* maximum input line size */

        int max;
        char line[MAXLINE];
        char longest[MAXLINE];

        int get_line(char line[], int maxline);
        void copy(char to[], char from[]);

        /* print longest input line */
        int main()
        {
            int len;    /* current line length */
            int max;    /* maximum length seen so far */
            char line[MAXLINE]; /* current input line */

            char *longest = malloc(0); /* longest */
            char *complete = malloc(0); /* complete */

            max = 0;
            while ((len = get_line(line, MAXLINE)) > 0) {
                int line_len = strlen(line);
                int complete_len = strlen(complete);
                complete = (char *) realloc(complete, strlen(line) + strlen(complete));
                strcat(complete, line);

                if (line[len - 1] == '\n') {
                    if (strlen(complete) > max) {
                        longest = (char *) realloc(longest, strlen(complete));
                        max = strlen(complete);
                        strcpy(longest, complete);
                    }
                    complete[0] = '\0';
                }
            }

            if (max > 0) /* there was a line */
                printf("%s", longest);

            return 0;
        }

        /* get_line: read a line into s, return length */
        int get_line(char s[], int lim) {
            int c, i;

            for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) {
                s[i] = c;
            }

            if (c == '\n') {
                s[i] = c;
                ++i;
            }

            s[i] = '\0';
            return i;
        }
          

Addendum, after reading 1-16 again, I think the question assumes you don't know about malloc, and instead to just print as much of the line as possible. Here's a re-work of the problem without malloc:

        /*print the longest line */
        main()
        {
            int len;            /* current line length */
            int total_len;      /* the total length when line spans multiple reads */
            int copied_size;    /* the size of the line copied */
            int max;            /* maximum length seen so far */
            char line[MAXLINE];     /* current input line */
            char longest[MAXLINE];  /* longest line saved here */

            max = 0;
            total_len = 0;
            copied_size = 0;
            while ((len = get_line(line, MAXLINE)) > 0) {
                total_len += len;
                if (total_len > max) {
                    max = total_len;
                    if (len > copied_size) {
                        copy(longest, line);
                        copied_size = len;
                    }
                }

                if (line[len - 1] == '\n') {
                    total_len = 0;
                }
            }

            if (max > 0) /* there was a line */
                printf("%d: %s", max, longest);

            return 0;
        }
      


---
20231114
        I think that it's extraordinarily important that we in computer science keep fun in computing.
        when it started out, it was an awful lot of fun.  Of course, the paying customers got shafted
        every now and then, and after a while we began to take their complaints seriously.  We began to
        feel as if we really were responsible for the successful, error-free perfect use of these
        machines.  I don't think we are.  I think we're responsible for stretching them, setting them
        off in new directions, and keeping fun in the house.  I hope the field of computer science never
        loses its sense of fun.  Above all, I hope we don't become missionaries.  Don't feel as if you're
        Bible salesmen.  The world has too many of those already.  What you know about computing other
        people will learn.  Don't feel as if the key to successful computing is only in your hands.
        What's in your hands, I think and hope, is intelligence: the ability to see the machine as more
        than when you were first led up to it, that you can make it more.

        Alan J. Perlis
      
        4. Every program is a part of some other program and rarely fits.
      
---
20231114
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

---
20231109
        15.
        The ancient masters were subtle, mysterious, profound, responsive.
        The depth of their knowledge is unfathomable.
        Because it is unfathomable, all we can do is describe their appearance.
        Watchful, like men crossing a winter stream.
        Alert, like men aware of danger.
        Courteous, like visiting guests.
        Yielding like ice about to melt.
        Simple, like uncarved blocks of wood.
        Hollow, like caves.
        Opaque, like muddy pools.

        Who can wait quietly while the mud settles?
        Who can remain still until the moment of action?
        Observers of the Tao do not seek fulfillment.
        Not seeking fulfillment, they are not swayed by desire for change.
      

---
20231109
The K&R book contains the example code snippet:
        /* copy: copy 'from' into 'to'; assume to is big enough */
        void copy()
        {
          int i;

          i = 0;
          while ((to[i] = from[i]) != '\0')
            ++i;
        }
      
This seems to imply to[i] = from[i] has the side-effect of returning the value from[i].

Consider:
        #include

        int main()
        {
            int a = 0;
            int b = 1;

            printf("%d", a = b );
        }
      
The results print 1 to stdout, showing the assignment of the value b is printed.

---
20231102
Confusing Git Terminology

---
20231101
The Tao Te Ching

---
20231031
        // Add a check for visitation which fixes 20231016 version.
        //
        // Note to self, visited could be a node state instead.
        fn dfs_iter(root: &Node, bound: usize) {
            let mut visited = vec![];
            let mut call_stack = vec![];
            let mut path = vec![];

            call_stack.push(root);
            visited.push(root);

            while !call_stack.is_empty() {
                let node = call_stack.pop().unwrap();

                path.push(node); 
                visited.push(node);
                let sum: usize = path.iter().map(|n| n.key).sum();

                if sum <= bound {
                    println!("* path: {:?}", path.iter().map(|n| n.key).collect::>() );

                    let descendants = &node.descendants;
            
                    for d in descendants {
                        call_stack.push(d);
                    }
                }

                if sum > bound || node.descendants.is_empty() {
                    path.pop();

                    // backtrack
                    loop {
                        let n = path.last();

                        match n {
                            None => break,
                            Some(n) => {
                                let is_explored = is_explored(n, &visited);
                                if is_explored {
                                    path.pop();
                                } else {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
      


---
20231030
Porting OpenBSD pledge() to Linux

---
20231016
        // note to self, the following iterative version does not produce the same
        // results as the recursive version from 20231014.  The reason being that
        // once a leaf node is reached, only one node is popped instead of popping
        // all the way to the root for example.  One possible way to solve this is
        // to add an explored state to each node and pop if the node is explored.
        // A node is explored if all of it's descendants are explored.
        //
        // iterative dfs bound by node sum.
        fn dfs_iter(root: &Node, path: &mut Vec, bound: usize) {
            let mut call_stack = vec![];
            call_stack.push(root);

            while !call_stack.is_empty() {
                let node = call_stack.pop().unwrap();
                path.push(node.key);

                let sum: usize = path.iter().sum();

                if sum <= bound {
                    println!("path: {:?}", path);

                    let descendants = &node.descendants;

                    for d in descendants {
                        call_stack.push(d);
                    }
                }

                if sum > bound {
                    path.pop();
                } else if node.descendants.is_empty() {
                    path.pop();
                }
            }
        }
      
---
20231015
How to Build a Universe That Doesn't Fall Apart Two Days Later

---
20231014
        // recursive dfs bound by node sum.
        fn dfs(node: &Node, path: &mut Vec, bound: usize) {
            path.push(node.key);
            let sum: usize = path.iter().sum();

            if sum <= bound {
                println!("path: {:?}", path);

                let descendants = &node.descendants;

                for d in descendants {
                    dfs(d, path, bound);
                }
            }   

            path.pop();
        }
      
        // dfs bound by distance. 
        fn dfs(node: &Node, distance: usize, bound: usize) {
            println!("key: {} depth: {}", node.key, distance);

            let descendants = &node.descendants;

            for d in descendants {
                let new_distance = distance + d.distance;
                  
                if new_distance <= bound {
                    dfs(d, new_distance, bound);
                }
            }   
        }
      
---
20231013
        // dfs - non binary tree that prints the distance from the root to the leaf (depth).
        fn dfs(node: &Node, distance: usize) {
            println!("key: {} depth: {}", node.key, distance);

            let descendants = &node.descendants;

            for d in descendants {
                dfs(d, distance + d.distance);
            }
        }
      
---
20231012 -
        // dfs - non binary tree that prints the depth of each node.
        fn dfs(node: &Node, depth: usize) {
            println!("key: {} depth: {}", node.key, depth);

            let descendants = &node.descendants;

            for d in descendants {
                dfs(d, depth + 1);
            }
        }
      
---
20231011
-
        // dfs - non binary tree
        fn dfs(node: &Node) {
            println!("{}", node.key);

            let descendants = &node.descendants;

            for d in descendants {
                dfs(d);
            }
        }
      
        // A Node definition.
        #[derive (Clone, Debug)]
        struct Node<\'a> {
            descendants: Vec>>,
            key: usize
        }
      
        // Building a tree to search on.
        //     5
        //   / | \
        //  3  1  4
        //  |
        //  2

        let node_five = Node {
            descendants: vec![
                Box::new(&node_three),
                Box::new(&node_one),
                Box::new(&node_four)],
            key: 5
        };

        ..
      


---
20231006
-
Introduction to Algorithms
-
        // A binary search - O(height)
        fn binary_search(node: &Node, target: usize) {
            if node.key == target {
                println!("found node that matches target: {:?}", node);
            }

            if target < node.key {
                let left_node: &Node = node.left.as_ref().unwrap();
                binary_search(left_node, target);
            }

            if target > node.key {
                let right_node: &Node = node.right.as_ref().unwrap();
                binary_search(right_node, target);
            }
        }
      
        // A Node definition.
        #[derive (Clone, Debug)]
        struct Node<'a> {
            left: Option>>,
            right: Option>>,
            key: usize
        }
      
        // Building a tree to search on.
        let node_five = Node {
            left: Some(Box::new(&node_three)),
            right: Some(Box::new(&node_seven)),
            key: 5
        };

        ..
      


---
20231002
-
Dictionary of Algorithms and Data Structures
-
Customizing Git Configuration
-
How to Write a Git Commit Message



---
20230928
-
The Tao of Programming
-
      // If the input is a tree and not a graph (without cycles), then
      // the solution becomes simpler since there is no need to maintain
      // a visitied list.
      fn dfs_tree(tree: &HashMap>, root: usize) {
          println!("visit {}", root);

          let branches: &Vec = tree.get(&root).unwrap();

          for &node in branches {
              dfs_tree(tree, node);
          }
      }

      // The iterative version
      fn dfs_tree_iter(tree: &HashMap>, root: usize) {
          let mut s = Vec::new();

          s.push(root);

          while !s.is_empty() {
              let n = s.pop().unwrap();

              println!("visit {}", n);

              let branches = tree.get(&n).unwrap();

              for &n in branches {
                  s.push(n);
              }
          }
      }
      

---
20230926
-
    // Recursive depth first search.
    fn dfs(visited: &mut HashSet, graph: &HashMap>, vertex: usize) {
        // Check if the vertex has been visited.
        if !visited.contains(&vertex) {
            println!("visit {}", vertex);

            // It hasn't been visited, so mark it as visited now.
            visited.insert(vertex);

            // Get all edges of this vertex.
            let edges: &Vec = graph.get(&vertex).unwrap();

            // For each child, visit.
            for &v in edges {

                // Recusive call.
                dfs(visited, graph, v);
            }
        }
    }
    
    // Iterative depth first search.
    fn dfs_iter(visited: &mut HashSet, graph: &HashMap>, vertex: usize) {
        let l = graph.len();

        // The stack will never be larger than the graph. 
        let mut s: Vec = Vec::with_capacity(l);
        s.push(vertex);

        while !s.is_empty() {
            let v: usize = s.pop().unwrap();

            // Check if the vertex has been visited.
            if !visited.contains(&v) {
                println!("visit {}", v);

                // It hasn't been visited, so mark it as visited now.
                visited.insert(v);

                // Get all edges of this vertex.
                let edges: &Vec = graph.get(&v).unwrap();

                for &v in edges {
                    s.push(v);
                }
            }
        }
    }
    
    // Entry point.
    fn main() {
        // A hashmap of tuples which represent a graph.  The first item is the vertex, 
        // and the second item which are edges.  
        let mut graph = HashMap::from([
            (5 , vec![3, 7]),
            (3 , vec![2, 4]),
            (7 , vec![8]),
            (2 , vec![]),
            (4 , vec![8]),
            (8 , vec![])
        ]);

        let l = graph.len();

        // Start DFS at the root node 5.
        // Set of visited (no duplicates)
        let mut visited: HashSet = HashSet::with_capacity(l);
        dfs(&mut visited, &mut graph, 5);

        ..
    }
    
-
      echo "Editing files on a remote machine with vim"
      vim scp://username@hostname/
    
-
      cat .bash_profile
      eval $(keychain --eval --agents ssh id_ed25519)
    
-
      echo "setup keychain"
      cd /usr/ports/security/keychain/ && sudo make install clean
      echo "eval $(keychain --eval --agents ssh id_rsa)" > ~/.bash_profile
    
[1]
-
---
20230925
-
      cat .vimrc 
      execute pathogen#infect()
      syntax enable 
      filetype plugin indent on

      " ctrlp
      set runtimepath^=~/.vim/bundle/ctrlp.vim

      " fix backspace
      set backspace=indent,eol,start

      " Shortcut to rapidly toggle `set list`
      nmap l :set list!

      " tabstop:          Width of tab character
      " softtabstop:      Fine tunes the amount of white space to be added
      " shiftwidth        Determines the amount of whitespace to add in normal mode
      " expandtab:        When this option is enabled, vi will use spaces instead of tabs
      set tabstop     =2
      set softtabstop =2
      set shiftwidth  =2
      set expandtab
    
-
      cat .xinitrc

      # Set background image
      feh --bg-max ./Downloads/awesome-destop.jpg

      # Start evilwm
      /usr/local/bin/evilwm -snap 10
    
-
      echo "setting up the homepage droplet"

      # Add a new user
      sudo useradd -m {username} -s /bin/bash
      sudo passwd {username}

      # Add a sudoer
      vim /etc/sudoers
      user_name ALL=(ALL)  ALL

      # Setup Git
      sudo apt-get install git
      cd ~ && git clone git@github.com:yancyribbens/homepage.git

      # Setup nginx
      sudo rm /var/www/html/index.nginx-debian.html
      sudo ln -s ~/git/homepage/index.html /var/www/html/index.nginx-debian.html

      # Enable ssh for new user (copy the keys file from root)
      cp /root/.ssh/authorized_keys /home/yancy/.ssh/authorized_keys
      chown user:user /home/user/ssh/authorized_keys