Fatfile

This file contains the contents of every page in the wiki in no order whatsoever.

Problem Solving

Problem Solving Framework

The mnemonic I have settled on is PI AT PC. Plus I can imagine a a picture of a little pi symbol sitting at a computer in like 1994.

  • understand the Problem
    • Ensure you fully understand and grasp the problem. Try and replace any and all gooshy elements (e.g. pronouns, not-specific-enough words, anything vague) with a more clear revision.
  • IOCE the problem
    • Figure out your Inputs, Outputs, Constraints, and Edge cases. This is simpler for coding problems, but is still useful outside of it in bounding the problem and reducing the complexity of your desired solution.
  • figure out the problem's Assumptions
    • What can be assumed about this problem? About the input, output, constraints, or edge cases? This is where you can further probe for the bounds of the problem so you don't have to solve more problems or cases than necessary.
  • create Tests
    • How can you test that you have a solution and that it works? How can you test against the cases you know won't work? How can you test the edge cases? Be thorough, as a test that is not definitive is useless.
  • create Pseudocode/use Plain english
    • How would you describe a solution to someone without using jargon? Without knowing any technical knowledge, how would you describe how to solve this problem to another person?
  • Code/Create your solution
    • Do it!

Solving Larger Problems

Solving problems is the ability to break problems into smaller problems. Even if you don't instantly know how to solve it, and say "well, I'm probably going to need to do X and then Y", and can repeat that process for those sub-problems until you either know how to solve it, look it up, or ask someone.

Aptitude != Knowledge

The common thing to confuse "aptitude" with is "knowledge". I also talk about this when discussing interviewing with colleagues: many interviews check for "knowledge" (what does this function do? what is a hash? what does "CSS" stand for?) because it's easy to do and (presumably) because people mistakenly consider it a good heuristic for whatever makes someone a good developer. However, in general, "knowledge" is easy to get - go read wikipedia or a book or some documentation and memorize it. It's also not very useful - if you don't know something, go look it up! It helps because it makes you faster (not having to look everything up is why CPUs have instruction caches), and it might more quickly lead you toward a better solution (if you know several approaches already, you can more quickly consider which would be best), but much more important is "aptitude". It's much harder to teach someone how to think.

References

  1. https://www.reddit.com/r/adventofcode/comments/7kd8jt/what_would_you_say_are_the_minimal_skills_for/dre0uu3/

Last modified: 202110091810

Essays

Bill Watterson's "SOME THOUGHTS ON THE REAL WORLD BY ONE WHO GLIMPSED IT AND FLED"

When it seemed I would be writing about "Midnite Madness Sale-abrations" for the rest of my life, a friend used to console me that cream always rises to the top. I used to think, so do people who throw themselves into the sea.

Danny Barnes' "how to play in someone else's band {gain twenty years of road experience with a five minute read}"

your path for achieving success is two fold: 1. play great. 2. in all things, be easy to deal with.

Last modified: 202108300218

Bike Maintenance

Sticky/Unresponsive Road Shifters

If you are experiencing difficulty with your road shifters, it is likely that the grease inside of the mechanism has accumulated dust and no longer catches the shifting thingy. It may be good to mount the bike or place it upside down (much harder) so you can shift easily.

Squeeze the brakes until you see the inside of the shifting mechanism. Spray a liquid penetrant like Pb Blaster or Kroil (NOT WD40) inside of the mechanism and try shifting up and down repeatedly for a couple minutes. You should notice an improvement, but it probably won't be fixed. Wait and repeat in a couple of hours.

Once finished, get some compressed air and flush out any gunk in there, and some isopropyl alcohol if you want to be super thorough.

Derailleur Adjustment/Indexing

You will want the bike mounted or flipped upside down so you can pedal the bike for shifting gears.

Set the limit screws

On each derailleur, there is a high or "H" and a low or "L" screw. These maintain the limits of how far your derailleurs will go towards or away from the frame.

Shift to the lowest gear and adjust the "L" screw to where the derailleur is perfectly aligned with the gear. You will see it move side to side. If you don't, you're probably turning the wrong way. If it's not moving enough, you may need to adjust the cable length.

Repeat this process with the highest gear and the "H" screw.

Set the gear indexing

This will calibrate the gear shifting to not skip or go halfway on shift.

Start at the lowest gear. While "pedaling", shift to the next gear. This is when you are testing the fluidity of the shifting, so stop once the shifting is not occurring as expected.

If the shifting is not occurring as you'd like, you will want to adjust the barrel connectors until the derailleur is directly above the desired gear. On the front derailleur, it will be on the downtube; on the rear, it will be attached to the derailleur. As you adjust, you should see the derailleur move side to side.

Once the index is accurate, continue on to the next gears until complete.

Truing Your Wheels

Lateral Truing

Tools

  • Spoke wrench: Mine cost around $10 from REI and looks like a circle with three nubs on it. Anything will do as long as it matches the size of your tire nipples, which can be figured out through the use of a caliper.
  • Zip Ties: Any will do as long as they are long enough to wrap around the fork/tube tightly and still have some length on the other side (look at this video for reference).
  • Needlenose Pliers: Only necessary if you have flat spokes.
  • Lubricant (e.g. Tri-Flow [something that is not just a penetrant]): The spoke nipples may be super tight or stuck, so it's worth having something like this to keep things loose. I have also read of using some kinds of oil, but this lubricant will do the trick.

Set Up

Start off by taking the tire and innertube off of the tire. Sometimes the tire and tube can obfuscate the actual shape and curvature of the rim.

Place the zip ties on the fork (for the front tire) or the frame (for the back) perpendicular to the rim. You want to place them and clip their length so they can eventually be rotated closer and closer to the rim as your rim gets more and more straightened out.

    / _______ \   <-- FRAME
   / /  TIRE \ \
  / /  /```\  \ \ 
  | |  |\/\|  | |
  )-(--|/\/|--)-( <-- ZIP TIES

Mount your bike or flip it over onto the seat so that the tires can rotate freely during testing.

Process

In short the process is:

  • find the area where the rim is most out of alignment
  • make a very small adjustment towards the desired alignment
  • repeat both steps until finished

Here is the process in detail:

  1. Set the zip tie a few millimeters away from the edge of the rim. The goal at this step is to ensure that through a full rotation, the zip tie doesn't touch the rim, but gets close.
  2. Rotate the zip tie inward towards the tire about as little as you possibly can.
  3. Spin the wheel slowly, watching and listening for the zip tie to make contact with the edge of the wheel.
  4. Repeat steps 2 and 3 just until a zip tie makes contact with the rim. You want the least amount of contact with the rim possible.
  5. Once you make contact, manually rotate the wheel, watching and listening for the loudest (most out of alignment) section. Aim for finding an area about as wide as one or two spokes.
  6. Find the spoke nearest to this section that goes up towards the side of the hub opposite of the zip tie that is touching. For instance, if the zip tie on the right is touching the rim, you want to find the spoke that meets the hub on the opposite side of that zip tie.
  7. Place the spoke wrench on that spoke nipple and tighten it a quarter turn. Some important notes:
    • Tightening and loosening are done from the perspective from the tire side of the rim. It will probably feel like you are doing it wrong. Quoting bikebooboos.com, "Imagine using a screwdriver to tighten the nipple from the tire side of the rim, then turn the nipple the same way using a spoke wrench on the spoke side of the rim, and you’ll be fine."
    • You almost always want to tighten your spokes instead of loosening them. Avoid loosening as this could cause your spokes to loosen up while riding and destroy your wheel's integrity.
    • Don't do more than a quarter turn at a time! It's tempting, but be patient.
  8. Check the rim again, rotating the wheel around the same section. If you still hear the contact, go back to step 5 and repeat. If it has gone away, go back to step 2 and repeat.
  9. Once this process has been done repeatedly, you should have a relatively laterally true rim.

References

Last modified: 202110050153

stuff-to-do

Simple

Less Simple

  • learn toki pona
  • solve a rubix cube by figuring out algos myself
  • make a raytracer a la zserge's article
  • learn to juggle for a straight minute

Last modified: 202110211508

20210811202726-deploy-on-aws

MONGO

https://jasonwatmore.com/post/2019/11/18/react-nodejs-on-aws-how-to-deploy-a-mern-stack-app-to-amazon-ec2

  • Start up EC2 ^^

  • Log in

  • Install Node

  • Install Mongo

    • Import the public key used by the package management system: wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
    • Create a list file for MongoDB: echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list
    • Reload local package database: sudo apt-get update
    • Install MongoDB packages: sudo apt-get install -y mongodb-org
  • Start up Mongo

    • sudo systemctl start mongod
    • Verify it is running: sudo systemctl status mongod
    • Stop/restart: sudo systemctl stop mongod / sudo systemctl restart mongod
    • Use the shell: mongosh
  • Copy db data to instance

SERVER

  • start an ec2 instance

    • Amazon Linux
    • t2 micro
    • security, enable http on 80 and ssh on 22
    • use same pem as above
  • install repo

    • ssh in ssh -i pemfile ec2-user@blahblah
    • sudo yum install git
    • clone repo in git clone https://github.com/...
  • install node

    • curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
    • restart instance
    • nvm install node
    • . ~/.nvm/nvm.sh
    • node -e "console.log('Running Node.js ' + process.version)"
    • npm install -g npx
  • install nginx

    • sudo amazon-linux-extras install nginx1

    • sudo service nginx start

    • set up nginx config

      • sudo vim /etc/nginx/nginx.conf

      • Before the other location blocks within server {, insert:

        location / {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host      $http_host;
          proxy_pass       http://127.0.0.1:3000; 
        }
        
      • Also ensure that the port your server is listening for has been set within the server block

    • restart nginx

  • make nginx persistent

    • sudo systemctl start nginx
    • sudo systemctl enable nginx
  • npm install everything in your repo

  • Initiate your server

  • install redis

    • https://medium.com/@andrewcbass/install-redis-v3-2-on-aws-ec2-instance-93259d40a3ce

      sudo yum -y install gcc make # install GCC compiler
      cd /usr/local/src
      sudo wget http://download.redis.io/redis-stable.tar.gz
      sudo tar xvzf redis-stable.tar.gz
      sudo rm -f redis-stable.tar.gz
      cd redis-stable
      sudo yum groupinstall "Development Tools"
      sudo make distclean
      sudo make
      sudo yum install -y tcl
      sudo make test
      sudo cp src/redis-server /usr/local/bin/
      sudo cp src/redis-cli /usr/local/bin/
      
    • test by running redis-server & and check ports with sudo lsof -i -P -n | grep LISTEN. Should see port open with redis-server. Kill by running kill {PID}, pid being the number in lsof.

  • If you want your server to persist, use pm2

    • npm i -g pm2
    • run this pm2 startup and copy its output
    • run that output? I think
    • pm2 save
    • pm2 start nodemon path/to/server.js
    • This will allow the server to persist on logout and on server restart

Run It All

Mongo

  1. sudo systemctl start mongod

Server

  1. sudo service nginx start
  2. redis-server & npm start
  3. on close: sudo lsof -i -P -n | grep LISTEN and kill {PID} for redis

Other AWS stuff

Each Linux instance launches with a default Linux system user account. The default user name is determined by the AMI that was specified when you launched the instance.

  • For Amazon Linux 2 or the Amazon Linux AMI, the user name is ec2-user.
  • For a CentOS AMI, the user name is centos.
  • For a Debian AMI, the user name is admin.
  • For a Fedora AMI, the user name is ec2-user or fedora.
  • For a RHEL AMI, the user name is ec2-user or root.
  • For a SUSE AMI, the user name is ec2-user or root.
  • For an Ubuntu AMI, the user name is ubuntu.
  • Otherwise, if ec2-user and root don't work, check with the AMI provider.

References

Last modified: 202108270637

20210721184446-docker

From Eric Pearson / @nyloneric

Docker stuff until I make it pretty: Make the thing: https://flaviocopes.com/docker-node-container-example/**[flaviocopes.com](http://flaviocopes.com/)** Create a simple Node.js Hello World Docker Container from scratch https://flaviocopes.com/docker-node-container-example/You will run into errors, so: => [internal] load metadata for ``docker.io/library/node:14`` Solved with: sudo DOCKER_BUILDKIT=0 docker build . -t user/node-web-appdiscussion: https://stackoverflow.com/questions/64221861/failed-to-resolve-with-frontend-dockerfile-v0 doStack Overflow Failed To Resolve With FrontEnd DockerFIle.v0more details about docker file: https://nodejs.org/en/docs/guides/nodejs-docker-webapp/enter container: docker exec -it <container id> /bin/bash``docker run -p 49160:8080 -d <your username>/node-web-appPut your image in the cloud! https://hub.docker.com/signupNode.js Dockerizing a Node.js web app | Node.js Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.[1:25 PM] I also really like Mosh Hamadani tutorials. https://www.youtube.com/watch?v=pTFZFxd4hOI

Last modified: 202107220145

20201230_notes

Debugging

Programming is writing out a set of instructions for an interpreter to follow such that following those instructions will lead to solving a computational challenge.

Two sides of a bug

  1. The cause: some line or lines where your code is written in a way that leads to problemns
  2. The symptoms: program state, output - An undesired program state or output that you expected to be different than what you see the computer producing. Could be a function manipulating data wrong or a variable holding unexpected values.

Different kinds of bugs

  • Syntactic error: Whether or not your plan was good, a typo makes code unreadable to your interpreter.
    • Symptom: Syntax error, program won't start
    • Solution: go to line mentioned and fix typo
  • Semantic error: what you wrote did not do what you think it did. The interpreter used what you put, but what you gave was not what you, or maybe what the interpreter, expected.
    • Symptom: usually an error thrown later in the program, usually not where you wrote the error
    • Solution: Find the misstatement in your code
  • Logical error: The step by step plan you developed for solving the problem is somewhat misconceptualized or vague.
    • Symptom: the program throws an exception or produces undeired output
    • Solution: find the misconception in your plan

Goalposting

This is a variant on Divide and Conquer. When experiencing a bug, the first step is to set goal posts around the code that could possibly be a problem. From whichever direction you believe is most beneficial, test if an area is acting as expected using logging or a debugger or whatever. If it is, the goal post may be moved to that area, as we know it is doing what we expect. You should not move the goal post past anything you have not yet tested.

Last modified: 202107151447

20210811115011-docker

Docker

Make a dockerfile

FROM node:14

COPY package*.json ./
COPY tsconfig.json ./
COPY yarn.lock ./

RUN yarn install

COPY . .

RUN yarn build 

EXPOSE 3000 

CMD ["yarn", "start"]

Build

$ docker build -t NAME .

Run

$ docker run -dp 3000:3000 NAME

The package should now be available on your local machine

Last modified: 202108112346

20210626112245-aws-deployment

from Eric Pearson (@nyloneric): https://gist.github.com/NylonEric/372516f2fe3c9f708d20e7e2f77007cb#file-2021-06-23-md

June 23, 2021

Overview

Deploy all the things! http://frontendcapstone.com

Log

10:00om - 2:00am

Challenge/Motivation

Get repo onto AWS instance and connect through a persistant IP or domain name

Actions Taken

deploy! set up domain frontendcapstone.com w/ google domains (domains.google.com)

AWS

https://aws.amazon.com/ec2/getting-started/

set up security policy on AWS EC2 I started with everything open and then restricted to port 80 UDP/TCP traffic for incomming. I also openned ICMP traffic for pinging purposes as well as ssh port 22 for logging into server.

set up elastic IP so it will persist after reboot/termination

Linux/UNIX instance:

  • AMI name: amzn2-ami-hvm-2.0.20210617.0-x86_64-gp2

Logging in:

ssh from local: set permissions to pem file: chmod 400 hr-nylon-eric.pem

ssh -i hr-nylon-eric.pem ec2-user@ec2-35-172-51-196.compute-1.amazonaws.com

Then navigate to and create folder for project:

git clone https://github.com/Idakka/Project-Atelier.git
sudo yum install git

Setting up Node:

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
nvm install node
. ~/.nvm/nvm.sh
node -e "console.log('Running Node.js ' + process.version)"
npm install -g npx

router/ reverse proxy:

sudo amazon-linux-extras install nginx1
sudo service nginx start
  • message: Redirecting to /bin/systemctl start nginx.service
cat /etc/nginx/sites-available/default
  • this didn't work and I had to go find the etc/nginx/nginx.conf file and edit it with nano: sudo nano /etc/nginx/nginx.conf
 server { listen 80; server_name tutorial; location / {  proxy_set_header  X-Real-IP  $remote_addr; proxy_set_header  Host        $http_host; proxy_pass        http://127.0.0.1:3000; } }
  • Most of this config was filled out, Just needed to add the location block and change to port 1234 for our server

link config files

sudo service nginx restart
  • npm start in project folder, need ed to install nodemon

install webpack

npm install webpack
npm start
  • IT WORKS!!!

keep it running:

https://medium.com/hackernoon/tutorial-creating-and-managing-a-node-js-server-on-aws-part-2-5fbdea95f8a1#.mnlkymeti

npm i -g pm2
pm2 start tutorial/index.js
  • To make sure that your PM2 restarts when your server restarts pm2 startup
  • you will be given a custom string similar to this but specific to your machine, copy that: sudo env PATH=$PATH:/home/ec2-user/.nvm/versions/node/v16.4.0/bin /home/ec2-user/.nvm/versions/node/v16.4.0/lib/node_modules/pm2/bin/pm2 startup systemd -u ec2-user --hp /home/ec2-user

save config with everything running (no nginx at this point) pm2 save

pm2 start nodemon server/server.js

That’s it! You can log out/in to SSH, even restart your server and it will continue to run on port 80.

  • To list all processes use pm2 ls

nginx persistent:

systemctl start nginx
systemctl enable nginx

having trouble restarting nginx on reboot, sudo systemctl enable nginx

  • is supposed to solve it. needed to start nginx/ make persistant and THEN redo the pm process

Results Observed

I got the app deployed pretty quickly but had to troubleshoot making the node server and nginx reverse-proxy persist after reboot.

Last modified: 202108151939

git

Commits

Add files you want to commit: git add {file or folder name}. You can also add all by using git add ., but this is not recommended, as you don't want to add all unless you are POSITIVE it doesn't contain cruft or unwanted changes, which is rarely the case. An easy way to check what has changed in your files since last commit is to use the --patch flag.

--patch

Add only portions of a file as 'hunks': git add --patch/-p {file or folder name} (file or folder is optional). This will prompt you with options:

  • y - stage this hunk
  • n - do not stage this hunk
  • q - quit; do not stage this hunk or any of the remaining ones
  • a - stage this hunk and all later hunks in the file
  • d - do not stage this hunk or any of the later hunks in the file
  • g - select a hunk to go to
  • / - search for a hunk matching the given regex
  • j - leave this hunk undecided, see next undecided hunk
  • J - leave this hunk undecided, see next hunk
  • k - leave this hunk undecided, see previous undecided hunk
  • K - leave this hunk undecided, see previous hunk
  • s - split the current hunk into smaller hunks
  • e - manually edit the current hunk (particularly if your code is really close together but needs to be broken down)
  • ? - print help

Case Sensitivity

Git by default is not case sensitive when it comes to filenames and will ignore renaming of file structures that are only by case. To change this default behavior, use git config core.ignorecase false. Note that setting this option to false on a case-insensitive file system is generally a bad idea. Doing so will lead to weird errors. For example, renaming a file in a way that only changes letter case will cause git to report spurious conflicts or create duplicate files.

If it is a file or files, you can change their name as normal and then within git via this command: git mv -f filename.txt Filename.txt. This will make it show up in your commit. If it is a directory, you will need to do this with every file within the directory.

Branches

Action Command
See all branches git branch
See the remote branches your local repo knows git branch -a
Checkout an existing branch git checkout {name}
Create and name a new branch git branch {name}
Create and checkout a new branch git checkout -b {name}
Create an orphaned branch git checkout --orphan {branch_name}
Push the current branch git push origin HEAD
Rename a branch. Assuming you're currently on the branch you want to rename git branch -m {name}
Delete a fully pushed and merged branch git branch -d {name}
Force delete a local branch git branch -D {name}
Merge another branch into currently checked-out branch git merge {other-branch}

Orphan Branches

Commits usually have one parent, their previous iteration. The root commit (very beginning) of your repo has none, and when you merge commit a fork with another branch or the master branch.

An orphan branch is a new root commit, where:

The first commit made on this new branch will have no parents, and it will be the root of a new history, totally disconnected from all the other branches and commits. In other words, it creates a new root commit and uses it as a starting point for your new branch.

Delete All Merged Branches

To delete all branches that have been merged, start out by pulling from remote to ensure you are using the most up to date info. Then check which branches are merged by running git branch --merged. We will be using egrep to grab these and put them into a macro that will delete each merged branch that doesn't fit within the regex. To ensure a branch that contains a certain keyword does not get deleted, add it to the egrep -v "(^...)" line, with each keyword separated by an OR |.

git branch --merged | egrep -v "(^\*|master|main|dev|staging)" | xargs git branch -d

Cherry Pick

When should I use cherry-pick? The short answer is: as rarely as possible.

For this reason, I have not spent much time learning how to get this to work, as the only experience I have had was one of my colleagues using this and causing hours of work trying to fix the side effects.

Revert

A revert allows you to go back to a previous commit, reversing those previous between commit X (HEAD) and commit Y (the selected commit). This will create a reversal commit for each commit to be undone between X and Y. In the case of a single commit to be undone, it will make a single reversal commit.

To revert one or many commits, open your git log and find the commit you want to revert back to. Save this hash. Then enter the following:

$ git revert [-m 1] <commit-hash>

The -m flag is used to revert a merge; to set where the mainline is, which parent you are wanting to revert back to. Most of the time it is 1.

For example, lets say you accidentally committed to the main branch and pushed up. You can revert this with git revert HEAD or git revert {hash}, creating a commit dialog and fixing your mistake through adding to your commit history.

Stashing

Stashing allows you to temporarily save changes without committing anything.

To stash some changes, use git stash save 'message about stash', or just git stash if you want to leave out the message.

To see what you have stashed, use git stash list to see all stashed code. Then see what is in each stash by using git stash show {index}, and you can see it diffed by using the -p flag.

Stashes can be listed recalled via the indexes shown: git stash apply {index} or git stash pop {index} if you want to remove it from the stashes after being applied.

You can git stash drop {index} individual stashes or git stash clear the entire stash.

Credentials

If you receive a message like this when trying to push up to your repo:

remote: HTTP Basic: Access denied
fatal: Authentication failed for 'https://gitlab.com/myusername/repo.git'

or

remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/milofultz/tod.git/'

Then you may have revoked or renewed your token and need to reset it. To do so, type this in the terminal:

$ git credential reject

And when you receive a new line, enter in url= followed by the url that showed up previously in the error message. Then use ctrl-c or ctrl-d to quit.

url=https://github.com/milofultz/tod.git/

On trying to push again, you will get prompted for authentication and it will work.

Token

Github deprecated standard HTTPS for SSH, so if you continue to get this error, generate a new token and use that token in place of your password.

Errors

Handle Windows newlines (CRLF => LF): https://stackoverflow.com/questions/20168639/git-commit-get-fatal-error-fatal-crlf-would-be-replaced-by-lf-in/31144141#31144141

Meta

Simplify git Call

In your Bash or equivalent rc file, set an alias of g to git. Surprisingly has saved me quite a bit of mistypes and extra key typing.

Use VIM as Editor

  • Install Vim using homebrew
  • Set vim to be the default editor with git config --global core.editor "vim"

Good Commit Hygiene

References

  1. https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
  2. https://koukia.ca/delete-a-local-and-a-remote-git-branch-61df0b10d323
  3. https://bugfactory.io/blog/orphaned-brachnes-in-git/
  4. https://git-scm.com/docs/git-add
  5. https://devconnected.com/how-to-cherry-pick-git-commits/
  6. https://phoenixnap.com/kb/git-revert-last-commit
  7. https://stackoverflow.com/questions/41842149/error-commit-is-a-merge-but-no-m-option-was-given
  8. https://superuser.com/questions/1309196/how-to-update-authentication-token-for-a-git-remote
  9. https://www.git-tower.com/learn/git/faq/cherry-pick/
  10. https://stackoverflow.com/questions/17683458/how-do-i-commit-case-sensitive-only-filename-changes-in-git
  11. https://github.com/delventhalz/no-fear-git
  12. https://nfarina.com/post/9868516270/git-is-simpler
Backlinks

Last modified: 202110141553

Making a Good README

Your README file contains a high level overview for people interested in using, contributing, or perusing your code.

Structure/Content

  • Title
  • Overview - A brief description outlining what the project
  • Table of Contents - You can link to the different sections below using # followed by the lowercased and kebab-cased version of the header. e.g. Table of Contents => #table-of-contents
  • Description - A more detailed outline of the project. What does it do? Is there a high level list of features? If describing a project that has visual features, consider adding pictures or animations of the features and functionality in this section.
  • Installation - How can another developer get your project up and running on their own? What dependencies are required? Are there environmental requirements? Be specific, and outline steps to take in order to get the project running.
  • Usage - Further details on how the project is meant to be used may be helpful. For a library or framework, this section would outline how to use the library within another project. For a service that is meant to be used within a larger project architecture, instructions on how to integrate may be necessary.

Additionally, for some projects, additional information might make sense.

  • Related Projects - Links to other repositories that are related to the current one. Are there partner projects? Is there a newer version of this project elsewhere?
  • Team Members - Add the names of your team members. Describe roles on the team such as "Product Owner", "Scrum Master" and more.
  • Contributing - If you'd like others to be able to contribute to your work, outline a process through which they can submit a request for changes to be incorporated. More specifically, outline the Git workflow for these contributors. Should they use a feature branching workflow? Should they rebase or merge? Should the fork the repository? What is the review process?
  • Roadmap - What future enhancements are planned? What is the current status of the project? Is it being actively maintained?
  • License - If open source, state how the project is licensed.

Last modified: 202107020455

Vim

Vim is a command-line editor that is included with most *nix machines and OSX.

Commands

All commands must be done in "Normal" mode, accessed by pressing esc if in write mode. Commands are case sensitive and must be confirmed with Enter unless otherwise noted.

Meta/File

Description Command Notes
Quit :q
Quit and do not save :cq
Save and quit ZZ No need to confirm or press enter.
Save :w
Save and quit :wq
Save only if file changed and quit :x
Save As :w newFileName

Undo/Redo

Description Command Notes
Undo u
Redo Ctrl + R

Find

Description Command Notes
Find /searchpattern Go to next occurrence with n and previous with N
Find and Replace :1,$s/searchpattern/replacepattern To replace all, add /g to the end of the command

Navigation

Description Command Notes
Go to beginning of file gg
Go to end of file G
Go to beginning of line 0 / ^
Go to end of line $

Copy (Yank), Cut, and Paste

Copy is "yank" in Vim, so that's why they are "y".

Description Command Notes
Copy entire line or n lines, including newline nyy
Copy from cursor to end of line y$
Copy from cursor to start of line y^
Cut entire line or n lines, including newline ndd
Cut from cursor to end of line d$
Cut from cursor to start of line d^
Paste after the cursor p
Paste before the cursor P

Delete

Description Command Notes
Delete line dd
Delete 3 lines 3dd
Delete from current column to end of line D

Misc

Description Command Notes
Toggle fold at next logical break za

Plugins and Packages

  • Ultimate vimrc - This is a great starting point that includes a lot of fantastic plugins and settings
  • Emmet

References

Backlinks

Last modified: 202110212237

Glue Work

[0:10:32] Glue work is the meta work that helps keep the organization running and on track. e.g. scrum master stuff; fixing problems, increasing fluidity in between teams, creating coding standards for ease of production, etc.

[0:12:12] If you are only doing glue work and not your actual job, it may be beneficial but it is hurting your own career and potentially your ability to keep your job or get promoted.

[0:14:31] What do you want to get better at? Do more of that and get better at it. Find something that you will be happy and proud to do. When we start at a job, we are bad and then get better.

[0:18:30] Since certain fields just assume if you left a certain job you lost all of those skills, which of those doors are you willing to close to open some others?

[0:19:43] Have the career conversation with the boss about "when will I be promoted", "What do I need to do to do so", etc. Write them down for later.

[0:20:17] If you find yourself doing a whole lot of X, get a title that shows that you do X a lot.

[0:21:23] Create a story that shows that "because of the work X I did, Y was able to happen. It happened because of the work I did."

[0:22:22] If your colleagues, managers, etc. do not care about the glue work you are doing, stop doing it and only do what is on your job description. If your goal is to get promoted, a raise, etc. and what you need to get those promotions is not being done, focus only on your job description and achieving those goals until that goal is achieved. Push away requests that are not your problem. [0:23:20] Do not catch things that are about to drop. Do not try and fix what is broken. It is not your problem if they are not willing to reward you for your work.

[0:24:07] How are you spending your finite work hours? If it is not on the things that are bringing you towards your goals, be it happiness, a promotion, or whatever, do not do those things. Focus only on what you need. [0:24:46] You will only learn what you spend time on, so learn deliberately and spend time on the things that will reward you most. [0:25:26] Be public about learning and let people know what you've been working on. [0:26:02] Don't take learning opportunities from others if you know how; give them the work that will help them learn.

[0:26:25] "You should do X because you are so good at it." "Yes I am good at whatever I spend a lot of time on, you should see me doing Y."

References

  1. https://www.youtube.com/watch?v=KClAPipnKqw
Backlinks

Last modified: 202107021505

Best Practices (Programming)

Writing Code

  • Programming isn't about the stack or the systems architecture; the arch meta will change faster than you can learn it.
  • The number of frontend Frameworks out there are N+1.
  • DRY, recursive funcs, polymorphism are [typically] afterthoughts and should not be a goal while you're developing the solution.
  • TAKE TIME OFF. If you have 24 hrs time off that's three days office time. TAKE. THEM. AND. GO. AFK. It's best to plan the time and let your team know. Try to make it non-work related (but not self-destructive): camping, reading, visit family, practice hobbies, volunteering with animal shelters, study fine art, date people .... Make memories. Please, just live your life.
  • Understand what good testing means. If you have trouble with this, look at tests on github of frameworks/languages. The basic form of tests come in the following for Javascript for front/back end devs (Node.js specific?): Unit Tests, Integration Tests, End-to-end tests. Understand why they're utilized and how to leverage them for various use-cases.
  • Read the documentation. It's your job to understand what's going on internally for your stack's framework(s) and if it takes you a few days to estimate the work-cost of utilizing a new lib reading docs is time well spent. If management doesn't understand this time after time then look for a new place to work.
  • Buy you a whiteboard. Plan your work on it - sprints, logic, component relationships, cat drawings. (and of course it doesn't have to be a whiteboard, but the open space of a whiteboard to track my weekly meetings, logic intuitions, etc. all are best expressed for me in a large space)
  • Keep a journal if you can (or a blog/vlog/written notes if that's the way you track your thoughts). Reflecting on the way I thought about a problem or feature set has been the best way for me to recognize my growth. (e.g. In college we never really discussed the implications of "Immutability" though it was mentioned and I found that as I kept journaling my understandings of Immutability with the context of the problems at hand it helped to give me a portrait of how/when to utilize it for future projects more effectively.)
  • "Make it correct, make it clear, make it concise, make it fast. In that order." - Wes Dyer
  • "Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, Structure and Interpretation of Computer Programs

Job/Soft Skills

  • The job of a programmer on a team is to communicate. You will not get a better application from all-nighters, you will not 'free solo' an application. All systems are the sum total of the discussions, joint planning, and hard work. Any product you concoct alone, devoid of communication, will fail in a team-based env. (though, shared all-nighters in a team session have been some of the best moments in my career, so take this one with a pinch of salt)
  • Few tho they are, programming "rock stars" exist: you will see them on NPM and may even work beside them or read their blog posts, but these are outliers. (Read "Outliers" by Malcom Gladwell for better context than I can provide). I had the opportunity of working with an "Outlier" and though my understanding of programing appreciated from that time, the codebase suffered (and still suffers) from it.
  • Kanban's will keep your team in check. Stay on top of your tracking especially if your portion is behind; it's not a mechanism of doubt or shame or illness or anything that contributed to you being behind on work. Your honesty is tantamount: when your peers start to doubt your abilities you're already in a bigger hole than you probably are. Learn to communicate the nature of your issues with the problem at hand and I guarantee that your peers will recognize it if not in whole than in part. Speak up!
  • Tell your boss to have patience. But first, learn how to tell your boss to have patience.
  • Sprint estimations for new features are, in the practical sense, a fallacy. Feature-sprints are pretty loose unless you work with a team that's one-out-of-a-thousand. Pad your dates by a factor of 2 where you can. (2 months = 4 months, etc. - also depends on your team size.)
  • If your team consistently underestimates the time needed for a patch/feature (sprints) after 1.5/1.75 yrs time consider leaving unless you (or management) can really commit to change in this regard.
  • "Glue Work." In the scope of dev, there are no enemies. Not your boss's boss, not your boss, not your team members, not your clients, not you. Company culture is usually your first culprit if things go wrong, and if you can't vocalize why/how then it requires one of two things: a contractor to debug your company culture OR for you to leave; there is (in my experience) no middle ground here. (Unless it's your job to fix it, at least learn how to recognize Glue Work: https://www.youtube.com/watch?v=KClAPipnKqw)
  • If you work for a non profit, make sure your worldview is in line with the org's mission statement and that those you work with harbor your own sentiments. If not, leave.
  • Do not interview for new jobs with/on company property or during work hours. Even if you have consent to do so, just don't. Wait until lunch, wait until you're home to compose your email resp to an offer. Cover your bases legally especially in the realm of startups.
  • When looking for jobs, ask about their testing practices. If they don't really answer, obfuscate their response, or just dont have an answer, avoid them at all costs. Tests/testing are a symptom of a healthy company culture.
  • Learn/Practice vocalizing thoughts such as "I think you're wrong, here's why..." and "I don't think that's right given ..." and "While that's part of the problem an equally (if not more) pressing issue is ..." It's important to learn how to vocalize your misgivings, even if you're not 100% confident about them; your intuitions about a given problem will usually find similar minds on the team chip-in and fill the gaps.
  • Empathy. Empathy for your co-workers, empathy for your clients, empathy for your past-self too. Practice empathy.

Self Development

  • Make a habit of reading books if not directly related to dev then tangentially related. (4 books per year was a good pace for me.)

References

  1. https://www.reddit.com/r/webdev/comments/kzqmhb/im_in_awe_of_you_all/
  2. https://softwareengineering.stackexchange.com/questions/43151/should-you-sacrifice-code-readability-with-how-efficient-code-is
  3. https://www.infoq.com/articles/no-hotfix-deployment/

Last modified: 202109172212

XML

There's currently nothing here.

Backlinks

SVG

SVG's are scalable vector graphics. They consist of instructions for the computer to follow to create the drawing.

An SVG file is an XML markup file and thus is super simple to create yourself. All SVG's start out with an outer svg element.

<svg version="1.1" width="300" height="200" viewBox="x1 y1 x2 y2" xmlns="http://www.w3.org/2000/svg">
  <!-- Version is not necessary -->
  <!-- W/H set during render, can be overwritten via CSS -->
  <!-- Viewbox is the part of grid to be shown  -->
  <!-- xmlns is required only for SVG files, not inline HTML -->
</svg>

Drawing Shapes and Paths

SVG's use a grid system, where positive X is right and positive Y is down. The top left of the document is then 0, 0.

By default, renderings that come first, are placed below renderings that come later.

<svg ...>
  <rect ...></rect>      // Behind the circle
  <circle ...></circle>  // On top of the rect
</svg>

You can group SVG elements in a <g> container, and all transformations made on the container will occur to their children.

Path

The path element is how you "pick up" and "put down" your "pen", as well as draw the lines which can make up a filled shape or just a stroked line. The directions go within the d attribute.

M x y is when you place your pen a given position without a stroke. L x yis when you draw a line to (x,y) from your starting point.

<!-- This will move the pen to (0, 10) and draw a line to (10, 0) in the given box -->
<path d="M 0 10 L 10 0"></path> 

Shapes

Rectangles are drawn with the rect element.

Circles are drawn with the circle element, with a center X/Y and a radius.

<circle cx="50" cy="50" r="50"/>

Other polygons are drawn with the polygon element and a series of X,Y points separated by spaces.

<polygon points="0,100 50,25 50,75 100,0" />

External file or inline HTML?

External files allow the computer to only have to load the data once and then reuse it throughout the page. If you have it written out multiple times, that is a lot of extra work.

References

  1. https://stackoverflow.com/questions/18467982/are-svg-parameters-such-as-xmlns-and-version-needed
  2. https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Positions
  3. https://developer.mozilla.org/en-US/docs/Web/SVG/Element
  4. https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths
  5. https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle
  6. https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon

Last modified: 202107020546

Javascript

There's currently nothing here.

Backlinks

Regular Expressions

Regular Expressions or "regex" is used to describe a series of characters. If it has a pattern in its formatting, regex can be used.

Regular Expression Syntax

This syntax is for Javascript, but it is mostly what I have used in everything so far.

Metacharacters

  • ^ at the beginning means that the match must start with what follows.
  • $ at the end means that the match must end with what precedes it.
  • . means any character that is in that place is allowed. e.g. /h.llo/ will return a match on "hello", "hallo", "hullo", etc.
  • * means match the preceding character or group 0 or more times.
  • + means match the preceding character or group 1 or more times.
  • ? means the preceding character is optional in the match. (e.g. /gre?a?y/ matches 'grey', 'gray', and 'gry')
  • +? means match as few instances of the preceding character or group as possible.
  • x|y means x or y.
  • \ is used to escape characters.
  • [abc] means one of the characters within the brackets ('a' 'b' or 'c') must be present at that position. This can include one or more ranges of characters, which are notated with a hyphen (e.g. 'a-z', 'A-Z', '0-9'). Adding a ^ within the brackets means anything but what is inside.
  • x{n} returns a match if a x is found n number of times. n can be a range separated by a comma (e.g. {2,4}). A single comma and nothing succeeding it means at least n times (e.g. {2,} means at least 2 times).
  • () indicate that whatever is within them should be grouped together, in instances of curly braces for instance.

Shorthand Character Classes

  • \w is any alphanumeric char or underscore.
  • \W is anything but an alphanumeric char or underscore.
  • \d is any digit.
  • \D is anything but a digit.
  • \s is any whitespace character.
  • \S is any non-whitespace character.
  • \b denotes a word boundary. Placed after a string of chars, it matches if the string is found and is succeeded by anything but an alphanum or underscore.

Lookahead and Lookbehind

Lookahead and lookbehind allow search queries that will not be included in the final match. e.g. x(?=y) will return x only if succeeded by y.

Lookahead

  • x(?=y) will match x only if it is followed by y.
  • x(?!y) will match x only if it is not followed by y.

Lookbehind

  • (?<=y)x will match x only if it is preceded by y.
  • (?<!y)x will match x only if it is not preceded by y.

Flags/Suffixes

  • i means the preceding search is case insensitive. If i is absent, it is case sensitive.
  • g means it will search for all instances, not just the first one it finds.
  • m means multiline search

Backreferences

\1, where 1 is any incremental number, is called a backreference. The number is referring to the capture group of the current reg ex. When called, the regex will search for the exact instance found of that regex.

For example, /[A-Z][0-9]\1/ will search for any char between A-Z, 0-9, and whatever character was found in the first character group. If you were searching through 'A9A' it would be a success, while 'A9B' would fail. This is because capture group 1 found an 'A', and therefore the backreference (\1) must also find an 'A'.

Common Regex Queries

Regex Matches
[\s\S] Anything
[^\n\r] Anything except for a newline
[A-Za-z0-9] Alphanumeric characters
[A-Za-z] Alphabetic characters
[0-9] or \d Numeric characters
[\.,-\/#!$%\^&\*;:{}=\-_`~()@\+\?><\[\]\+] All punctuation (non alphanum graphic characters)

References:

  1. https://regular-expressions.mobi/backref.html?wlr=1
  2. https://regexr.com/
  3. https://regexcrossword.com/
Backlinks

Last modified: 202107020457

Job Interviews

What are you trying to get from this position? What do they want from you in taking this position?

Questions to Ask

  • Of the people you know doing this job, what is that person like, and what are they doing in that position?
  • What is a typical day?
  • What is the work environment and company culture like?
  • What are the goals for the company? Short term and long term
  • How would performance be measured?
  • What are the company policies for learning and development?
  • Who was your best hire and why?

Last modified: 202110080420

Express

Express is a Javascript-based server application that will help route requests from the client.

Getting Started

First, start your project with npm init in the project folder. Then npm i express. Now you can start implementing the barebones in your project.

// app.js
const express = require('express');
const app = express();
const port = 3000;

app.listen(port, () => console.log(`Listening on port ${port}`));

To get it running, set up your package.json with a script to run. You can also use nodemon to run and restart upon file changes.

"scripts": {
  "start": "node app.js",
  "dev": "nodemon app.js"
}

Upon running one of these scripts (npm run start/dev), you should see a message in your terminal that your app is listening on port 3000.

Routes

// Parameters: `route`, and `callback` when request and response objects are received and created 
app.get('/', (req, res) => {
  data = 'We did it!';
  res.send(data);
});

Upon completing this and restarting your server, you should be able to go to localhost:3000 and see "We did it!" in your browser window.

Query Parameters

You can access the query parameters via the req.query object.

// .../products?example=1?another=five
app.get('/products', (req, res) => {
  const example = req.query.example;
  const another = req.query.another;
  res.send(JSON.stringify([example, another]));
});

References

  1. http://expressjs.com/en/starter/installing.html
  2. https://stackoverflow.com/questions/17007997/how-to-access-the-get-parameters-after-in-express
  3. https://expressjs.com/en/starter/static-files.html
Backlinks

Last modified: 202110211522

React

React is a Javascript framework for implementing dynamic single page applications into your site.

Setting Up

Use create-react-app with npm or build it from scratch.

Components

Components are reusable pieces of JSX that can be used to dynamically render HTML. The JSX is written as is, outside of any quotes. When components are referenced, they are written with the closing /. Components are named in PascalCase.

Note the parentheses used in the arrow function instead of curly braces. This is because the implicit return will enclose everything within the parentheses and allow it to be placed on multiple lines.

const FoodItem = () => (
  <li>Get some of this food!</li>
);

const GroceryList = () => (
  <ul>
    <FoodItem />
    <FoodItem />
  </ul>
);

These are rendered via the render method of the ReactDOM, which takes the component followed by the destination it will be appended to. Most common is that you will have a single div that your whole website will be injected into, i.e. <div class="app"></div>.

ReactDOM.render(<GroceryList />, document.getElementById('main'));
<!-- output in associated HTML file -->

<div id="main">
  <ul>
    <li>Get some of this food!</li>
    <li>Get some of this food!</li>
  </ul>
</div>

Component Properties, or Props

Properties are attributes that can be passed into and used to populate parts of that component. Props are always passed in as an object of keys that correspond to the attributes given on the JSX element. e.g. <Component name={"John"} age={6} /> will pass { name: "John", age: 6 } into the Component. Props are surrounded by curly braces when they are assigned and when they are recalled. Inside the curly braces, valid Javascript may be called.

const GroceryListItem = (props) => (
  <li>{props.item.toUpperCase()}</li>
);

const GroceryList = (props) => (
  <ul>
    {props.groceryItems.map(propItem => <GroceryListItem item={propItem} />)}
  </ul>
);

ReactDOM.render(
  <GroceryList groceryItems={['candy', 'cookies', 'ice cream']} />, 
  document.getElementById('app')
);
<!-- output in associated HTML file -->

<div id="app">
  <ul>
    <li>CANDY</li>
    <li>COOKIES</li>
    <li>ICE CREAM</li>
  </ul>
</div>

Default Props

const GroceryListItem = (props) => (
  <li>{props.item.toUpperCase()}</li>
);

GroceryListItem.defaultProps = {
  item: 'Milk',
};

const GroceryList = (props) => (
  <ul>
    <GroceryListItem />
  </ul>
);

ReactDOM.render(<GroceryList />, document.getElementById('app'));
<!-- output in associated HTML -->

<div id="app">
  <ul>
    <li>MILK</li>
  </ul>
</div>

PropTypes

You can add type checking to your props to make your code a bit more robust. If the types you entered don't match the element's type, then it will only give a warning in the console and will still render (as long as it is able).

Primitive types in PropTypes:

  • array
  • bool
  • func
  • number
  • object
  • string
  • symbol

You can also specify .isRequired at the end of your propType definition.

import PropTypes from 'prop-types';

const GroceryListItem = (props) => (
  <li>{props.item.toUpperCase()}</li>
);

GroceryListItem.propTypes = {
  item: PropTypes.string.isRequired;
};

Exporting Components

You can put the component into another file and import it in by using the export default componentName syntax.

// GroceryListItem.js
const GroceryListItem = (props) => (
  <li>{props.item.toUpperCase()}</li>
);

export default GroceryListItem;
// app.js
import ...
import GroceryListItem from './GroceryListItem.js';

ReactDOM.render(
  <GroceryListItem item="candy" />, 
  document.getElementById('app')
);

Higher Order Components

Higher order components are just higher order functions in React, in that they are functions that spit out another function based on what is input. One example is a React HOC that takes in a component and adds logging capabilities to it. Since it is wrapping the entire element

import ...

const TrackingWrapper = ({ WrappedComponent }) => {
  return class extends React.Component {
    constructor(props) {
      super(props);
    }

    logInteraction(event) => {
      const logObject = {
        timstamp: Date.now(), 
        element: event.target
      };
      console.log(logObject);
      // POST to server
    }

  render() {
    return (
      <div className="tracking-wrapper" onClick={this.logInteraction}>
        {/* This will pass in all props passed to the WrappedComponent in their given namespace */}
        {/* Equivalent to the spread operator on a function definition */}
        <WrappedComponent {...this.props} />
      </div>
    )
  }
};

export default TrackingWrapper;

User Interaction/Event Listeners

Components can have local event listeners assigned directly to themselves.

const GroceryListItem = (props) => {
  const onListItemClick = function (e) {
    console.log("Yum!");
  };

  return (
    <li onClick={onListItemClick}>{props.item}</li>
  )
};

If you want to use an event listener on a class component that will be used within another this context, you need to be sure you maintain the correct this, either through bind, or the more sexy use of an anonymous arrow function.

// Good
return (
  <li onClick={this.onListItemClick.bind(this)}>{props.item}</li>
)

// Better
return (
  <li onClick={() => this.onListItemClick()}>{props.item}</li>
)

Stateless Functional vs. Class

All of the previous examples have used stateless functional components, which are declared at runtime and essentially become a static web page. If you want to have user interaction and a dynamic webpage, you will want to include state. State is just a dynamic memory for a given component, e.g. whether it has been clicked or has a given property. State is only included on class components and is initialized in the constructor.

First you will want to convert your stateless functional component into a class component.

class GroceryListItem extends React.Component {
  constructor (props) {
    super(props);
  }

  render () {
    return (
      <li>{this.props.item}</li>
    )
  }
};

Then you can add your state to the element via the class. When this.setState is called, the element rerenders in the DOM, applying whatever changes you have made to the state and control flow of the rendering of the element.

class GroceryListItem extends React.Component {
  constructor (props) {
    super(props);

    this.state = {
      hover: false,
    };
  };

  onClick () {
    this.setState({
      hover: !this.state.hover,
    });
  };

  render () {
    const style = {
      fontWeight: this.state.hover ? "bold" : "normal"
    };

    return (
      <li style={style} onClick={this.onClick.bind(this)}>{this.props.item}</li>
    );
  };
};

For the element to properly rerender, you must update the state by using the setState method. This will cause what React calls "reconciliation", which will update what needs to be updated in the DOM.

setState

The setState call takes in two arguments: setState(updated, [callback]):

  • updated: this is an object containing the state's properties as keys and the values that will be set within the state at those keys.
  • [callback]: an optional argument; this function will execute once only after the state has been set. Uesful for handling API calls and other asynchronous patterns with updating.

References

  1. https://reactjs.org/docs/introducing-jsx.html
  2. http://jamesknelson.com/javascript-return-parenthesis/
  3. https://stackfan.com/loop-through-an-array-of-objects-in-react/
  4. https://css-tricks.com/understanding-react-setstate/
  5. https://reactjs.org/docs/react-component.html#setstate
  6. https://reactjs.org/docs/typechecking-with-proptypes.html
  7. https://www.npmjs.com/package/prop-types
Backlinks

Last modified: 202110081411

Model View Controller

This design pattern is used to separate functionality, logic, and component management. MVC can feel or seem confusing because there is not one way to do it, and many different frameworks that utilize MVC do it differently from one another.

Components

Model

The model is the brain of the application, responsible for getting and manipulating the data. It is often interacting with some kind of database or data in a file.

The model is often communicating with the controller, which is requesting data and/or updating the view. Sometimes the updating of the view is delegated to the model, sometimes to the controller.

View

This is what the user interacts with. In web development, this is usually made up of HTML and CSS.

The view is usually told what to show by the controller by being given dynamic values, usually with some kind of template engine, like Handlebars, ERV, HAML, Jinja2, etc.

Controller

The controller takes in user input and decides what to do with it. Usually the user interaction with the browser will go through some kind of router which will then give the controller a specific method to execute.

The controller acts as a middleman between the controller and the view. It takes the user input, passes it to the model which will then return some data to the controller, who then tells the view what to display to the user.

Example Frameworks Using MVC

  • Ruby on Rails
  • Sinatra
  • Laravel
  • Codeigniter
  • Zend
  • Express
  • Backbone
  • Angular
  • Django
  • Flask
  • React (view)

References:

  1. https://www.youtube.com/watch?v=pCvZtjoRq1I
  2. https://www.youtube.com/watch?v=DUg2SWWK18I

Last modified: 202107020452

Magic Numbers (Programming)

Magic numbers are numbers that have no semantic meaning within the program. These are problematic for maintenance and bug fixing since somebody reading the code later could have no idea what exactly the numbers represent.

/* BAD: Magic Numbers */
function calculateTotal(price) {
  return price + price * 0.09 + 2;
}

/* GOOD: Semantic Meaning! */
function calculateTotal(price) {
  const taxRate = 0.09;
  const serviceCharge = 2;
  const calculatedTax = price * 0.09;

  return price + calculatedTax + serviceCharge;
}
Backlinks

Last modified: 202107080231

Accessibility

Checklist

Use this checklist to ensure you are doing your best to meet accessibility requirements.

Contrast

There needs to be a contrast of at LEAST 4.5:1 between the background and foreground of colors for readability.

"In WCAG 2, contrast is a measure of the difference in perceived "luminance" or brightness between two colors (the phrase "color contrast" is never used). This brightness difference is expressed as a ratio ranging from 1:1 (e.g. white on white) to 21:1 (e.g., black on a white)."

Examples

Bad

References

  1. https://webaim.org/resources/contrastchecker/
  2. https://webaim.org/articles/contrast/
  3. https://www.a11yproject.com/checklist/
  4. https://www.w3.org/WAI/test-evaluate/#tools
Backlinks

Last modified: 202107020546

Applescript

Applescript is a programming language used to create scripts in Mac computers.

Variables

set variableName to value

Destructure a list to new variables

set newList to {100, 200, 300}
set { x, y, z } to newList # x=100, y=200, z=300
set a to item 2 of newList # a=200

Have Application Do Something

tell application "iTerm" to \# put actions here

tell application "iTerm"
  \# put actions here
end tell

Actions

  • activate - Run program
  • open "Macintosh HD:Users:username:..." - Open file at filepath
  • close window 1 - Close window
  • set size of front window to {640, 400} - Set window size (x, y)
  • set position of front window to {0, 0} - Set window position (x, y)
  • set bounds of front window to {300, 30, 1200, 900} - Set window size and position {X-start, Y-start, X-end, Y-end}; corresponds directly to pixels of display resolution

Comments

-- This is a single line comment
\# This is another single line comment
(* This is
   a multi
   line comment *)

References

  1. http://downloads.techbarrack.com/books/programming/AppleScript/website/files_&_folders/opening_files.html
  2. Error Messages

Last modified: 202107020557

grep

grep finds string patterns within a given file or folder.

$ grep PATTERN dir/file.name
$ grep 'THIS THAT' dir/file.name

Regular Expressions

Square brackets do the same as normal, and also includes special POSIX groups, that do what you assume: [:alnum:], [:alpha:], [:blank:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:], and [:xdigit:].

Search with OR, AND, NOT

OR

$ grep 'PATTERN1\|PATTERN2' dir/file.name

AND

$ grep PATTERN1 dir/file.name | grep PATTERN2

NOT

$ grep -v 'NOTPATTERN' dir/file.name

Chain together a NOT with a regular search

$ grep 'THIS' dir/file.name | grep -v "NOT THIS'

Options

Options with a single hyphen can be combined and placed after grep. Double hyphen options are separated.

$ grep -rin PATTERN file.diz
  • -r: search recursively within a folder
  • -i: ignore case of search pattern
  • -n: print line number where pattern is found
  • -h: suppress filename from output
  • --color: color the output where pattern is found
  • --include=GLOB: search only files whose base name matches GLOB using wildcard matching (e.g. $ grep --include=*.md PATTERN)
  • --exclude-dir=dir_name or --exclude-dir={multiple,dir_names}

Output Formatting

You can use awk to print out a formatted output. -F and the following char is where in the string awk will split. Each split section can be called using $NF, with NF being the number of the field we want. $0 is everything.

grep IDEA | awk -F: '{print $1}'

References

  1. https://www.man7.org/linux/man-pages/man1/grep.1.html

Last modified: 202105310508

NPM

Node Package Manager is a hub from which you can install, manage, and maintain node/Javascript projects. NPM is bundled with node, so of you have installed node, you have npm.

Troubleshooting

Global Packages Not Found

If you have installed a package globally (npm i -g {package}) and you can't use because it is "not found", try the below steps.

  1. npm list -g --depth=0 - This should show your package.
  2. npm bin -g - Take note of this directory.
  3. npm config set prefix - Take note of this directory as well.
  4. Create a place for your npm global packages to reside and set your path to point to them:
mkdir ~/.npm-global  # this could already exist. If so, skip.
npm config set prefix ~/.npm-global  # If your prefix is already set to here, you can skip.
export PATH=~/.npm-global/bin:$PATH
source ~/.profile
  1. Try installing your package once again globally.

devDependencies

You can save packages as a devDependency by using --save-dev as an option in the CLI.

devDependencies are for the developers of the project. Things like test frameworks, documentation, etc. If someone downloads and uses your project, they won't have the dev dependencies installed. If someone wants to build on your project, they can download the dev dependencies.

References

Backlinks

Last modified: 202110172241

MongoDB

MongoDB is a NoSQL database management system based on Javascript using documents similar to JSON.

Getting Started

This will start a new project using your local server and mongoose via node.

Local Machine

Install MongoDB using brew services install mongodb-community. Once installed, you can start your local server using brew services start mongodb-community (Be sure to stop the server when completed with your work using brew services stop mongodb-community).

In the terminal, start the mongo shell: mongo.

Database

Creating a new database is done when a query is made.

Node

Create a new folder and initialize a new node project using npm: npm init -y. Then install npm i mongoose.

Create a new file called server.js and copy this into the contents:

  const mongoose = require('mongoose');                // import Mongoose
mongoose.connect('mongodb://localhost:27017/test', { // create connection to localhost
  useNewUrlParser: true, 
  useUnifiedTopology: true
});

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {                            // Inside here is where the action happens
  // Create schema for collection
  const kittySchema = new mongoose.Schema({
    name: String,
    color: {
      type: String,
      enum: ['brown', 'orange'],
    },
  });
  const Cat = mongoose.model('Cat', { name: String }); 

  const kitty = new Cat({ 
    name: 'Zildjian',
    color: 'orange'
  });         // Create a new document of Cat
  console.log(kitty.name);                             // 'Zildjian'
  kitty.save()
    .then(() => console.log('meow'));                   // Save the new document in the Cat collection
});

In the terminal, run node server.js. This should log 'Zildjian' along with meow.

Indexes

If your collection does not have an index, your query could take a very long time, as it will have to scan every single document within your collection and analyze it to see if it matches your query.

// create an index in collectionName from highest score to lowest
db.collectionName.createIndex( { score: -1 } )

Import and Export

mongoexport: Export JSON or CSV

$ mongoexport --db=dbName --collection=collectionName --out=filename.json

When you export in CSV format, you must specify the fields in the documents to export.

# for CSV etc.
$ mongoexport --db=dbName --collection=collectionName --fields=name,address --out=filename.json

mongoimport: Import JSON, CSV, or TSV

Use mongoimport to bring in Extended JSON, CSV, or TSV files to your Mongo database. First, start up your database, and then use mongoimport in the command line:

#             use the PetHotel db      use header line as field names
$ mongoimport --db=PetHotel --type=csv --headerline --file=pets.csv

# If no header line is availabe:       list them out after the --fields option
$ mongoimport --db=PetHotel --type=csv --fields=_id,name,type --file=pets.csv

Types

You can specify the types of the columns within the header line of your CSV.

id.int32(),summary.string(),recommend.boolean(),helpfulness.int32()
1,"This product was great!",true,8
$ mongoimport --db=PetHotel --type=csv --headerline --columnsHaveTypes --file=pets.csv

Null Values

If you have null values in your CSV, you can remove these null values between two commas (or after one if at the end of a line) and tell mongoimport to --ignoreBlanks. This won't import null values, but when interacting with your database, you can use the $exists query operator to query for them and $ifNull to cast missing fields as null in an aggregation pipeline.

In the below example, the summary is null, but we still want it to accept strings.

id.int32(),summary.string(),recommend.boolean(),helpfulness.int32()
1,null,true,8

If we were to import this as is, we would end up with a summary field containing an empty string. After replacing the ,null, with ,, and using --ignoreBlanks on import, this field ends up missing, which is the desired behavior.

To query for fields that have a missing of null field:

> db.collection_name.find({ summary: { $exists: false }})

And to get the field back with a null value in the place of that missing field:

> db.collection_name.aggregate([
... // match document with id of 1
... { $match: { id: 1 }},
... // show all fields and cast summary to null if missing
... { $project: {
...   _id: 0,
...   id: 1,
...   summary: { $ifNull: [ '$summary', null ]},
...   recommend: 1,
...   helpfulness: 1
... }}
... ]);

mongodump: Export BSON (native format)

To export a collection or database from a mongo database, use mongodump.

$ mongodump --db=dbName --collection=collectionName --out=path/for/output

mongorestore: Import BSON (native format)

To import a collection or database from a dumped mongo database, use mongorestore.

$ mongorestore -d dbName ./dump/path

Clone Database

You can clone a database on the same server using the following command:

$ mongodump --archive --db=dbName | mongorestore --archive  --nsFrom='dbName.*' --nsTo='newDbName.*'

Data Modification

If you need to modify data that already exists in a document due to a bad import or whatever, you can run a command like this in the mongo shell to change the values in place.

Let's assume a collection of dogs:

[
  {
    "_id": ...,
    "name": "Doggo",
    "goodBoy": "true", // should be a boolean
    "enemy": "null",   // or could be "mailman" or other string
  },
  ...
]

When completed, this will change all goodboy properties to a boolean and if enemy was imported with null as the string, it will convert it into an actual null value. The bulkWrite is done as it is much faster than sending individual requests.

var requests = [];
var cursor = db.dogs.find({});

cursor.forEach(item => {
  requests.push({ 
    "updateOne": {
      "filter": { "_id": item._id },
      "update": { 
        "$set": { 
          "goodBoy": Boolean(item.goodboy),
          "enemy": item.enemy === 'null' ? null : item.enemy
        }
      }
    }
  });

  if (requests.length === 1000) {
    // Execute per 1000 operations and re-init
    db.dogs.bulkWrite(requests);
    requests = [];
  }
});

if (requests.length) {
  db.dogs.bulkWrite(requests);
  requests = [];
}

Syntax

Command Effect
show dbs List all databases on the given server
use database_name Enter into database_name, preparing to query.
db.dropDatabase() Delete the selected database
show collections / show tables List all collections/tables in the selected database.
db.collection_name.find() Return all documents in collection collection_name.
db.collection_name.find({name: 'John'}) Return all documents in collection_name whose name is John.
db.collection_name.insert({name: 'John', age: 40}) Create a document in collection_name (note: if a new collection is selected via use, this will create the new collection)
db.collection_name.renameCollection('newName', dropOld) Rename collection_name to newName and if drop old table if dropOld is true.

References

Backlinks

Last modified: 202108230454

Mongoose

Mongoose is an NPM package that allows a simple and schema'd Javascript entrypoint to your Mongo database.

Basics

Setup

Install mongoose: npm i mongoose and ensure your database is running.

Project

Create a new file called server.js and put this within.

// Initilize database

const mongoose = require("mongoose");
const dbName = "test";
mongoose.connect(`mongodb://localhost:27017/${dbName}`, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

// Create test schema

const testSchema = new mongoose.Schema({
  name: String,
  age: Number,
  friends: [String],
});

// Create a model from your schema

// this first param is the name of your collection in your test database
const Test = mongoose.model("test", testSchema);

// Connect to database

const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", () => {
  console.log(`Mongoose DB "${dbName}" initialized\n`)
});

This will have created your basics. You can now start creating queries, inserting items into your database, etc.

Schemas and Models

Basic schemas are written very simply using a standard JSON format.

The following schema is for a registration form. It has five fields, all with differing implementations. Most basic, you can just put the key followed by it's type. If you want extended functionality, you can utilize it by using object notation.

const attendeeSchema = new mongoose.Schema({
  firstName: {
    type: String,
    required: true,
  },
  lastName: String,
  email: {
    type: String,
    required: true,
    match: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/,
  },
  shirt: {
    type: String,
    enum: ['XS', 'S', 'M', 'L', 'XL', 'XXL'],
    required: true,
  },
  skillLevel: {
    type: String,
    enum: ['beginner', 'intermediate', 'expert'],
  }
});

Once your schema is created, you will then create a model that will be utilized within your code.

// mongoose.model(collection, schema), where collection is the
// name of the collection in your database.
const Attendee = mongoose.model('attendee', attendeeSchema);

This makes it easy to encapsulate the whole thing inside of a file for export in a node project.

const mongoose = require('mongoose');

const attendeeSchema = new mongoose.Schema({
  ...
});

const Attendee = mongoose.model('Attendee', attendeeSchema);

module.exports = Attendee;

Remote Database

mongoose.connect('mongodb://username:password@host:port', {useNewUrlParser: true});

Troubleshooting

Return Object

The return of a query is not a plain Javascript object and will show weird behavior when trying to add to/remove from/modify it. If you want a plain Javascript object in return, you can use .lean() within your chain to cast it.

References

  1. https://mongoosejs.com/
  2. https://stackoverflow.com/questions/33614229/how-to-use-mongo-mongoose-to-connect-to-a-remote-database
  3. https://mongoosejs.com/docs/connections.html
Backlinks

Last modified: 202108162339

CSV

There's currently nothing here.

Backlinks

TSV

There's currently nothing here.

Backlinks

Postgres

Postgres is a relational database management system.

Getting Started

This tutorial will be for getting started with Postgres using node on a Mac.

Local Machine

Installation

Install Postgres using homebrew: brew install postgres

In a new terminal window, start up the local database: postgres -U username -d database_name, filling in the blanks as needed. If this does not work, ensure you have the local database installed at your username. The DB can be also started using brew services start postgres (Be sure to stop the server when completed with your work using brew services stop postgres).

To enter into interactive mode, in your terminal, enter psql. From here, you can enter in any queries you'd like. Ensure they all end with a semicolon, or else you will not get any return back and it will throw.

Initialization

Create a new table in your database: CREATE TABLE numbers( age integer );

Insert a value into the new table: INSERT INTO numbers VALUES (732);

Javascript

Initialize a new npm project, and then install pg, pg-format, and express.

Create a new file in your project called server.js and copy this into it's contents:

const express = require('express'); // Server
var pg = require('pg');             // Postgres 
var format = require('pg-format');  // For dynamic SQL queries (a la MySQL ?)

const app = express();              // Start your server

var PGUSER = '<your username>';     // Definte the username and database
var PGDATABASE = '<your username>'; // previously set up in Postgres.

var age = 732;                      // Used so we can reference our earlier insertion.

var config = {
  user: PGUSER,
  database: PGDATABASE,
  max: 10,                          // max number of clients in the pool
  idleTimeoutMillis: 30000          // how long a client is allowed to remain idle before being closed
};

var pool = new pg.Pool(config);     // Create a new connection instance

pool.connect(function (err, client, done) { // Connect to the DB
  if (err) {
    console.log(err);
  }
  app.listen(3000, function () {     // Connect to the Express server
    console.log('listening on 3000')
  });
  // Build a dynamic query using `age`
  var ageQuery = format('SELECT * from numbers WHERE age = %L', age);
  // Query the DB for all rows from the numbers table where age is = 732
  client.query(ageQuery, function (err, result) {
    if (err) {
      console.log(err);
    }
    console.log(result.rows[0]);
  });
});

Now in your terminal, run node server.js and assuming the database is still running, if should return:

listening on 3000
{ age: 732 }

Schemas

Schemas are within a database but are ways of organizing tables, objects, functions, etc. within the database. In a database with table1, table2, and table3, a schema could hold table1 and table2, with another schema holding table2 and table3.

To create a schema, use CREATE SCHEMA name, followed by the other components.

CREATE SCHEMA schema_example
  CREATE TABLE people(
    id INT PRIMARY KEY,
    name TEXT NOT NULL,
    age INT,
    birthday DATE
  )
  CREATE VIEW john_club AS
    SELECT 
      *
    FROM
      people
    WHERE
      name = 'John';

Querying JSONB Columns

The way to retrieve the values found at given columns in a JSONB column is by using the single or double arrow, -> and ->> respectively. The former will retrieve the value in its original type, while the latter will return the value as a string.

SELECT
  column_name -> 'property_name' AS display_name
FROM
  table_name;

Commands

Command Description
\dt Display all tables in the database
TABLE x Show the contents of table x.
SELECT schema_name FROM information_schema.schemata; Show all schema in a given database

References

  1. https://hub.packtpub.com/how-setup-postgresql-nodejs/
  2. https://www.postgresqltutorial.com/postgresql-show-tables/
  3. https://www.postgresqltutorial.com/postgresql-create-schema/
  4. https://www.guru99.com/postgresql-view.html
  5. https://gist.github.com/Kartones/dd3ff5ec5ea238d4c546
  6. https://www.postgresqltutorial.com/postgresql-cheat-sheet/
  7. https://kb.objectrocket.com/postgresql/how-to-query-a-postgres-jsonb-column-1433
  8. https://www.postgresql.org/docs/12/functions-json.html

Last modified: 202108102041

Common SQL Queries

These are some common SQL queries that come up. All ? symbols represent a place where you would dynamically insert info, like with Node's MySQL module.

Retrieval

Get the info from all rows with a given email

SELECT * FROM example_table
  WHERE email = ?;

See if more than one entry exists with a given email

SELECT email, COUNT(email) 
  FROM example_table
  GROUP BY email
  HAVING COUNT(email) > 1;

References

Backlinks

Last modified: 202105310620

SQL

SQL is a Structured Query Language that uses a relational database. A relational database represents a collection of related 2D tables, like spreadsheet. Tables of information about a certain thing hold rows that are specific instances of that thing with columns that show shared characteristics of those instances.

Database schemas describe the structure of each table and the datatypes that each column can contain.

Basic Syntax Rules

The end of a query is denoted with a semicolon.

Comments are made with --.

Whitespace and line returns are optional but often added for readability.

SQL queries are case insensitive, but by convention, the SQL commands and keywords are place in all capital letters to be easier to read by humans.

Creating/Using Databases

First, you want to see what databases exist using the SHOW DATABASES keyword.

SHOW DATABASES;

We will use the CREATE DATABASE keyword to initialize a database. TO enter into the database

CREATE DATABASE name;
USE name;

Creating/Altering Tables

SHOW TABLES;

CREATE TABLE / IF NOT EXISTS

What it sounds like, will make a new table. Use IF NOT EXISTS to skip if table exists. The structure of the table is defined by its table schema, which is a series of columns in the following parentheses.

CREATE TABLE friends (
  column DataType TableConstraint DEFAULT dafault_value,
  ...
);
CREATE TABLE IF NOT EXISTS dogs (
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  dog_name VARCHAR(10),
  good_boy INTEGER DEFAULT 1  -- Boolean, default is TRUE
);

ALTER TABLE

Choose the table you want to modify with ALTER TABLE followed by the table name. Columns can be added by using the ADD COLUMN statement, removed by using the DROP statement, and renamed with RENAME TO.

ALTER TABLE dogs
RENAME TO dog_types
ADD COLUMN breed VARCHAR(20) AFTER col_name  -- can also use FIRST
DROP dog_name;

DROP TABLE / IF EXISTS

(Necessary XKCD): "Little Bobby Tables"

DROP TABLE will remove an entire table and all of the data from the database. IF EXISTS will make sure no error is thrown if the table doesn't exist.

DROP TABLE IF EXISTS problems;

Table Data Types

Data type Description
INTEGER, BOOLEAN The integer datatypes can store whole integer values like the count of a number or an age. In some implementations, the boolean value is just represented as an integer value of just 0 or 1.
FLOAT, DOUBLE, REAL The floating point datatypes can store more precise numerical data like measurements or fractional values. Different types can be used depending on the floating point precision required for that value.
CHARACTER(num_chars), VARCHAR(num_chars), TEXT The text based datatypes can store strings and text in all sorts of locales. The distinction between the various types generally amount to underlaying efficiency of the database when working with these columns. Both the CHARACTER and VARCHAR (variable character) types are specified with the max number of characters that they can store (longer values may be truncated), so can be more efficient to store and query with big tables.
DATE, DATETIME SQL can also store date and time stamps to keep track of time series and event data. They can be tricky to work with especially when manipulating data across timezones.
BLOB Finally, SQL can store binary data in blobs right in the database. These values are often opaque to the database, so you usually have to store them with the right metadata to requery them.

Table Constraints

Constraints are a special expression in the table's initialization that directs the table to operate in a specific way.

CREATE TABLE IF NOT EXISTS products (
  product_id INT AUTOINCREMENT,
  name TEXT,
  PRIMARY KEY(product_id)
);

CREATE TABLE IF NOT EXISTS reviews (
  review_id INT AUTOINCREMENT,
  product_id INT,
  FOREIGN KEY(product_id)
    REFERENCES products(product_id)
);
Constraint Description
PRIMARY KEY This means that the values in this column are unique, and each value can be used to identify a single row in this table.
AUTOINCREMENT For integer values, this means that the value is automatically filled in and incremented with each row insertion. Not supported in all databases.
UNIQUE This means that the values in this column have to be unique, so you can't insert another row with the same value in this column as another row in the table. Differs from the PRIMARY KEY in that it doesn't have to be a key for a row in the table.
NOT NULL This means that the inserted value can not be NULL.
CHECK (expression) This allows you to run a more complex expression to test whether the values inserted are valid. For example, you can check that values are positive, or greater than a specific size, or start with a certain prefix, etc.
FOREIGN KEY This is a consistency check which ensures that each value in this column corresponds to another value in a column in another table. For example, if there are two tables, one listing all Employees by ID, and another listing their payroll information, the FOREIGN KEY can ensure that every row in the payroll table corresponds to a valid employee in the master Employee list.

Queries/Retrieving Data

SELECT...FROM statements are queries of column FROM table. DISTINCT will remove results that are the same, meaning that they have matching sets of columns in the return. Certain columns could have duplicate values, but ALL of the columns need to match up to another result for it to be considered a duplicate.

SELECT columnName, anotherColumn 
FROM tableName;

SELECT DISTINCT columnName, anotherColumn 
FROM tableName;

WHERE

The WHERE clause helps filter out results via a condition. AND or OR can be used to chain these.

SELECT columnName, anotherColumn 
FROM tableName
WHERE a = b
  AND a = c
  OR c = b

Results of a query can be sorted via the ORDER BY keywords, followed by ASC or DESC (ASC is the default).

SELECT columnName, anotherColumn 
FROM tableName
WHERE a = b
ORDER BY columnName ASC;

Results can also be tested against whether a column's value is within a list of values.

SELECT columnName, anotherColumn 
FROM tableName
WHERE a IN ('list', 'of', 'values');

LIMIT/OFFSET

Results can be limited via the LIMIT and the OFFSET keywords. "The LIMIT will reduce the number of rows to return, and the optional OFFSET will specify where to begin counting the number rows from."

...
LIMIT num_limit OFFSET num_offset

CONCAT

CONCAT allows you to group the values of multiple fields together and call it a new 'field' upon return. CONCAT can take multiple arguments and strings to affix together.

SELECT * 
FROM clients c
WHERE c.client = 17
  AND c.client IN (
    # The following line combines the values of `active_client` and `alt_clients`, separated by a comma 
    # and effectively creates a new field called 'all_clients'.
    SELECT CONCAT(active_client, ',', alt_clients) AS all_clients 
    FROM users
    WHERE userId = 7070
  );

JOIN

We can join the data within two or more tables with the JOIN clause. The two tables can be linked by a certain column with ON followed by an expression. (note: OUTER is added in as a legacy keyword for SQL-92)

  • INNER: Using something that is constant among both tables, usually a key like ascending numbers like IDs or a common string, this will create rows containing both table's data. This will exclude any data that is not found in both tables at that common key.
  • FULL (OUTER): This will keep all rows from both tables within the query, even if a matching row does not exist within one of the tables.
  • LEFT (OUTER): This keeps anything from the table found after FROM (Left), even if no matching row is found in the table found after JOIN (Right).
  • RIGHT (OUTER): This keeps anything from the table found after JOIN (Right), even if no matching row is found in the table found after FROM (Left).

Inclusive/Exclusive

Inclusive JOINs will use the ON table1.key = table2.key, matching one column to another. Exclusive JOINs follow this with a filter on the focused table set to WHERE table.key IS NULL.

Where n is the two table's intersection, u is the union of the two tables, and - is exclusion.

  • INNER: AnB
  • LEFT (Including RIGHT): Au(AnB)
  • LEFT (Excluding RIGHT): A-B
  • RIGHT: (AnB)uB
  • RIGHT (Excluding LEFT): B-A
  • FULL/OUTER: AuBu(AnB)
  • OUTER (Excluding INNER): (A-B)u(B-A)
-- This is a venn diagram with both circles fully selected
SELECT * 
FROM table1
FULL JOIN table2 -- or INNER or LEFT, etc.
  ON table1.id = table2.id
-- This can be altered to exclude what overlaps
WHERE table1.id IS NULL 
  OR table2.id IS NULL

AS

Expressions, columns, and tables can all be given aliases using the AS keyword.

SELECT col_name AS foo -- 'col_name' has been aliased to 'foo'
FROM table_name AS bar; -- 'table_name' has been aliased to 'bar'

Aggregate Functions

Aggregate functions run on the entire column. They include operations like COUNT, MIN, MAX, AVG, and SUM, with the desired columns surrounded by parentheses.

-- returns a single entry with number of entries in col_name
SELECT COUNT(col_name) 
FROM table_name;

-- returns a single entry with lowest ERA of all pitcher data
SELECT MIN(era) 
FROM pitcher_stats;

These functions can also be run on subsections of these columns using GROUP BY, followed by which segments should be calculated together.

-- returns an entry for the player with lowest ERA on each team
SELECT player_name, 
  MIN(era) FROM pitcher_stats
GROUP BY team_name;

Further filtering of what should be included in each GROUP can be done with HAVING, which operates like WHERE on the GROUP BY element.

-- returns an entry for the player with lowest ERA above 2 on each team
SELECT player_name, 
  MIN(era) FROM pitcher_stats
GROUP BY team_name
HAVING era > 2;

EXISTS - Boolean Check

You can use SELECT EXISTS (...) with an enclosed query to return either a 0 (false) or 1 (true) on if any rows were returned.

-- will return 1 if any rows are found where the name field contains 'John'
SELECT EXISTS (
  SELECT * 
  FROM example_table
  WHERE name = 'John'
);

Order of Query Execution

  1. FROM and JOIN (loading in data)
  2. WHERE (filtering data)
  3. GROUP BY (creating groups)
  4. HAVING (filtering data for each group)
  5. SELECT (selecting the columns)
  6. DISTINCT (removing duplicates)
  7. ORDER BY (organizing results)
  8. LIMIT and OFFSET (limiting results)

Adding/Changing Rows

INSERT INTO / VALUES

The INSERT INTO statement describes which table will have data inserted, and the VALUES statement includes all the values of the given row that will go into each column enclosed by parentheses and separated by commas within it. VALUES can correspond to multiple rows by separating the sets of values by commas.

With incomplete data or default values, you can choose which exact columns you want to add data to by following INSERT INTO table_name with a set of columns within parentheses and separated by commas. Inserting data this way ensures forward compatibility, as any new columns that are hardcoded into later versions of the table will not be affected.

INSERT INTO mytable (column_name, another_column_name)
VALUES (value_or_expr, another_value_or_expr),
  (value_or_expr_2, another_value_or_expr_2);

UPDATE / SET

UPDATE is followed by the name of the table, with SET followed by column_name = value_or_expr pairs. These can be used in conjunction with WHERE to filter which rows you want updated.

It is recommended to query the items you are going to update before updating them, to ensure you are correctly select what you want.

-- Update all costs of candy in food I like by raising them 3%
UPDATE food_i_like
SET cost = cost * 1.03,
  updated = "2021-01-01"
WHERE 
  type = "candy";

DELETE FROM

The DELETE statement describes the table to focus on, with WHERE describing which rows to delete (leaving out WHERE will delete the entire table!). If you only are trying to get rid of one thing, use LIMIT 1 to redundantly ensure you do.

It is recommended to query the items you are going to delete before updating them, to ensure you are correctly selecting what you want.

DELETE FROM food_i_like
WHERE name = "Good & Plenty"  -- always have WHERE to limit deletion
LIMIT 1;  -- always include this to limit deletion to ONLY one row

Variables

A SQL variable is defined by calling DECLARE followed by the variable name preceded by the @ symbol, after which you declare the type. To set the value, use the SET keyword followed by the assignment. In MySQL, you only use the SET keyword followed by either an equals or a colon-equals.

DECLARE @NewVariable AS VARCHAR(50);
SET @NewVariable = "Cool!";

Meta Operators

Name Function
(boolean expression) AND (boolean expression) WIll return true if both are true
(boolean expression) OR (boolean expression) Will return if either is true

Conditional Operators

Operator Condition SQL Example
=, !=, < <=, >, >= Standard numerical operators col_name != 4
BETWEEN … AND … Number is within range of two values (inclusive) col_name BETWEEN 1.5 AND 10.5
NOT BETWEEN … AND … Number is not within range of two values (inclusive) col_name NOT BETWEEN 1 AND 10
IN (…) Number exists in a list col_name IN (2, 4, 6)
NOT IN (…) Number does not exist in a list col_name NOT IN (1, 3, 5)
IS NULL/IS NOT NULL Value is or is not NULL col_name IS/IS NOT NULL

Expressions

Many different types of expressions can be used with: WHERE to better filter results; and SELECT to create new columns of results (column expressions). While there are a few different types of expressions, the examples below are both numeric type expressions. Expressions can also utilize aggregate functions.

-- Used in WHERE; filters above 0° Celsius
SELECT Temperature FROM 2000_Temp_Data
WHERE ((Temperature - 32) * 5) / 9 > 0;

-- Used in a column expression, displays another column named 'Celsius'
SELECT Fahrenheit, ((Temperature - 32) * 5) / 9 AS Celsius
FROM 2000_Temp_Data;

Formatting

There are many different opinions about how to format correctly (see below), but the one that I believe to be the most readable is formatted as such, with the capitalized INSTRUCTION on one line and lowercase args on the following line with indentation. Indentation is also used to define subqueries and bracketed blocks, with terminating brackets on their own line. AND and OR should start their lines and should not reside at the end.

SELECT
  r.last_name,
  (
    SELECT
      MAX(YEAR(championship_date))
    FROM
      champions AS c
    WHERE
      c.last_name = r.last_name
      AND c.confirmed = 'Y'
  ) AS last_championship_year
FROM 
  riders AS r
WHERE 
  r.last_name IN (
    SELECT
      c.last_name
    FROM 
      champions AS c
    WHERE 
      YEAR(championship_date) > '2008'
      AND c.confirmed = 'Y'
  );

There is a clearer and more dense formatting, but it seems like a pain to write. I may adopt it soon though:

SELECT r.last_name,
       (SELECT MAX(YEAR(championship_date))
          FROM champions AS c
         WHERE c.last_name = r.last_name 
           AND c.confirmed = 'Y') AS last_championship_year
  FROM riders AS r
 WHERE r.last_name IN (
        SELECT c.last_name
          FROM champions AS c
         WHERE YEAR(championship_date) > '2008' 
            AND c.confirmed = 'Y');

References

Schema Design:

Formatting:

Backlinks

Last modified: 202110232222

Yarn

Yarn is a hub from which you can install, manage, and maintain node/Javascript projects.

Installation

Yarn needs to be installed globally via NPM.

$ npm i --global yarn

Basic Commands

Command Args Effect
add n [--dev] n: Package name(s);
--dev: Add to dev dependencies
Adds package(s) to project
install Install all packages found in project
run n n: Name of script Run the script n found under scripts in package JSON
start Run the script found under scripts/start in package JSON
test Run the script found under scripts/test in package JSON

References

Backlinks

Last modified: 202110172302

SQLite

SQLite is an open-source, zero-configuration, self-contained, stand-alone, transaction relational database engine designed to be embedded into an application.

Data Types (version 3)

  • NULL
  • INTEGER
  • REAL (floating)
  • TEXT
  • BLOB (blob of data, stored exactly as it was input)

Primary Key

A column with type INTEGER PRIMARY KEY is an alias for the ROWID, which is always a 64-bit signed integer.

CREATE TABLE IF NOT EXISTS dogs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  dog_name TEXT,
  good_boy INTEGER DEFAULT 1  -- Boolean, default is TRUE
);

Foreign Keys

At the end of your schema, add the line FOREIGN KEY(col_name) REFERENCES foreign_table_name(foreign_col_name).

-- Referencing the above table `dogs`
CREATE TABLE IF NOT EXISTS owners (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT,
  dog_id INTEGER,
  FOREIGN KEY(dog_id) REFERENCES dogs(id)
);

Date and Time

Dates and times can be stored three different ways:

  • TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
  • REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
  • INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.

Date

Dates can be input as a string (formatted like "YYYY-MM-DD") via the date() function.

CREATE TABLE IF NOT EXISTS datetimes (
  date TEXT
);

INSERT INTO
  dates
VALUES
  (date("2021-10-01")),
  (date("2000-01-01"));

-- results in two rows being added as 
-- [("2021-10-01"), ("2000-01-01")] 

PRAGMA

PRAGMA commands are SQLite specific and are meta commands regarding operation or non-table data.

Get column information of a given table

PRAGMA table_info(table_name)

Use with shell

Open a SQLite3 database using the CLI. Install this shell using brew install sqlite3.

$ sqlite3 path/to/file.db

In this shell, you can make any query as normal.

Pretty Printing

You can output a ton of different types for display/output purposes using the .mode command:

  • ascii
  • box
  • csv
  • column
  • html
  • insert
  • json
  • line
  • list
  • markdown
  • quote
  • table
  • tabs
  • tcl

Output To File

# Choose the output mode
sqlite> .mode csv
# Set the output file
sqlite> .output output-file.csv
# Do your query
sqlite> SELECT * FROM table;

Use with Node

First, install sqlite3 with yarn or npm. Bring in the package in your new file and instantiate an in-memory database:

server.js

const sqlite3 = require('sqlite3').verbose();

const db = new sqlite3.Database(':memory:', (err) => {
  if (err) {
    return console.error(err.message);
  }
  console.log('Connected to the in-memory SQlite database.');
});

Instead of :memory:, you can also use the path to a SQLite database file.

Queries

db.run takes multiple arguments. First is the query itself, followed by an optional array of data to be escaped and injected, and lastly the callback which has a single error parameter.

// With escaped arguments

const sql = `
  SELECT
    *
  FROM
    table
`;

db.run(sql, function(err) {
  if (err) {
    return console.error(err.message);
  }
  console.log(`Row(s) updated: ${this.changes}`);
});

With escaped arguments:

const sql = `
  UPDATE
    table
  SET
    name = ?
  WHERE
    name = ?
`;
const data = ['Ansi C', 'C'];

db.run(sql, data, function(err) {
  if (err) {
    return console.error(err.message);
  }
  console.log(`Row(s) updated: ${this.changes}`);
});

Serialize and Parallelize

Using the db.serialize(() => {...}) wrapper will guarantee that the queries inside of it will complete before returning. For instance, running a table creation query and then trying to insert directly after won't work outside of a serialize wrapper because the db.run invocation returns immediately, thus not waiting for it to finish. The entire wrapper also waits for the inner queries to finish before returning anything, so is useful in database instantiation.

parallelize will not block and as far as I can tell, runs the same as if you put them all outside of the wrapper.

References

  1. https://sqlite.org/pragma.html#pragma_table_info
  2. https://www.sqlite.org/datatype3.html
  3. https://www.sqlite.org/lang_datefunc.html
  4. https://www.sqlitetutorial.net/sqlite-nodejs/connect/
  5. https://stackoverflow.com/questions/41949724/how-does-db-serialize-work-in-node-sqlite3
  6. https://formulae.brew.sh/formula/sqlite
  7. https://sqlite.org/cli.html
Backlinks

Last modified: 202110241515

argparse (Python)

argparse is a way to handle command line arguments in Python applications.

Getting Started

A simple application using argparse:

import argparse

if __name__ == "__main__":
    # What will show up using the built-in help
    argparser = argparse.ArgumentParser(description='Create wiki at output dir from input dir.')
    # Positional arguments
    # In `args` dict, var found at `input_dir`
    argparser.add_argument('input_dir', metavar='input', type=str, help='the path to the input directory')
    argparser.add_argument('output_dir', metavar='output', type=str, help='the path to the output directory')
    # Optional arguments with multiple flags
    # `action` defines what occurs if flag is set
    argparser.add_argument('--delete-current-html', '-d', action='store_true', help='delete all HTML in output directory before building')
    # `default` is the default value if not set
    # `dest` is the variable name set in `args` dict
    argparser.add_argument('--no-fatfile', '-nf', action='store_false', default=True, dest="build_fatfile", help='do not create fatfile on build')
    args = argparser.parse_args()

    # Use the args like so
    print(args.input_dir, args.output_dir)

argparse should not be used in the setup (i.e. not before the if __name__ == "__main__"), as this makes importing and testing impossible to do without a lot of extra work.

References

Last modified: 202110241513

Collections (Python)

These are some resources on how to use the collections Python package.

defaultdict(type)

from collections import defaultdict

counter = defaultdict(int)
counter["sheep"] += 1
print(counter["sheep"])  # 1
print(counter["dog"])  # 0

Will allow builtin methods based on the default type. defaultdict(int) will allow a += 1 on any key and it will be defined immediately if doesn't exist; (set) will allow .add(value) to a set and will create it if none exists, etc.

deque

from collections import deque

cards = [1,2,3,4]
deck = deque(cards)

top_card = deck.popleft()
deck.append(top_card)

# cards == [2,3,4,1]

If you need a copy of the deque, you will need to import the copy.deepcopy method, as slices don't work. If you need to slice, you can use itertools.islice.

Note that if you are looking for a queue, you can use a standard list as a queue by using list.pop(0) and list.append(item). It is much faster and requires no imports.

References

  1. https://docs.python.org/3/library/collections.html

Last modified: 202107181935

Itertools (Python)

Resources on how to use the itertools Python package.

itertools.product()

Avoid using nested for loops to iterate through multiple different lists or numbers

for var1 in xrange(min1,max1,step1):
  for var2 in xrange(min2,max2,step2):
    ...
      ...
        ...
          for var6 in xrange(min6,max6,step6):
            '''
            Do something and be icky in the process due
            to being in the middle of six nested for loops
            '''
x1 = xrange(min1,max1,step1)
x2 = xrange(min2,max2,step2)
x3 = xrange(min3,max3,step3)
...
for v1, v2, v3, v4, v5, v6 in itertools.product(x1, x2, x3, x4, x5, x6):
  icky_thing(....)

References:

  1. https://stackoverflow.com/questions/11174745/avoiding-nested-for-loops

Last modified: 202107020541

Virtual Environments (Python)

Virtual environments allow you to develop in a clean slate, leaving nothing to global packages and allowing easy installation by others.

You are in a virtual environment for your Python project when you see the env name (in this case, literally env) to the left of the bash prompt.

Create

cd to project folder and then type:

python3 -m venv env

Activate

cd to project folder and then type:

source env/bin/activate

Deactivate

deactivate

Last modified: 202107020544

Datetime (Python)

These are some resources on how to use the datetime Python package.

Using datetime

datetime.datetime.now().isoformat() - to get a string of the current date and time

References

Last modified: 202107020541

Debounce (Python)

How to create and use a debouncer in Python.

In both of these examples, the inner function won't run until at least DEBOUNCE_TIME seconds has passed.

Standalone

from threading import Timer
import time

DEBOUNCE_TIME = 1  # 1 second
debounced_action = None


def debounce_action(message: str) -> None:
    """ Print the last message to be invoked within a certain amount of time """
    global debounced_action

    def print_message():
        print(message)

    if debounced_action:
        debounced_action.cancel()
    debounced_action = Timer(DEBOUNCE_TIME, print_message)
    debounced_action.start()


if __name__ == "__main__":
    debounce_action("Won't print this one")
    time.sleep(.5)
    debounce_action("Or this one")
    time.sleep(.99)
    debounce_action("This one will though!")

The benefit of using this standalone is that you can have multiple items debouncing with the same inner function and different parameters by using a dict to store the different debounced_actions instead of using a singular global.

Decorator

from threading import Timer
import time

DEBOUNCE_TIME = 1


def debounce(wait):
    """ Decorator that will postpone a functions
        execution until after wait seconds
        have elapsed since the last time it was invoked. """
    def decorator(fn):
        def debounced(*args, **kwargs):
            def call_it():
                fn(*args, **kwargs)
            try:
                debounced.t.cancel()
            except(AttributeError):
                pass
            debounced.t = Timer(wait, call_it)
            debounced.t.start()
        return debounced
    return decorator


@debounce(DEBOUNCE_TIME)
def print_message(message: str):
    print(message)


if __name__ == "__main__":
    print_message("Won't print this one")
    time.sleep(.5)
    print_message("Or this one")
    time.sleep(.99)
    print_message("This one will though!")

The benefit of using a decorator is you can throw it on any function that needs debouncing at it saves you the reuse of the debouncing code in multiple places.

References:

  1. https://gist.github.com/walkermatt/2871026

Last modified: 202107212151

SQLite3 (Python)

How to use SQLite with Python.

Opening/Closing Connections and Command Execution

After importing the built-in sqlite3 module, you need to establish a connection with your database.

import sqlite3

conn = sqlite3.connect("database.db") # if found at filepath
conn = sqlite3.connect(":memory:")    # to use RAM (flushed after use)

After creating the connection, create a cursor object and use it to run SQL commands via execute.

c = conn.cursor()
c.execute("""--sql-goes-here""")

Once all commands have been run, be sure to commit your changes and close the connection.

conn.commit()
conn.close()

.fetchone() and .fetchall()

After you have executed a SELECT command, you can use the cursor as an iterator with fetchone(), which will recall each returned row one by one, or fetchall() to return all rows at once.

Outputting Dicts

You can output dicts instead of tuples by using the following from the docs:

import sqlite3

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

con = sqlite3.connect(":memory:")
con.row_factory = dict_factory
cur = con.cursor()
cur.execute("select 1 as a")
print(cur.fetchone()["a"])

con.close()

Pretty Printing

You can pretty print query resullts using the Pandas module.

import pandas as pd
import sqlite3

# set up the database

# Allow results to expand in width
pd.options.display.max_colwidth = 200

cursor.execute('''SELECT * FROM table''')
print(pd.DataFrame(cursor.fetchall()))

Get table names from database

SELECT name 
FROM sqlite_master 
WHERE type = 'table';

References

  1. https://docs.python.org/3/library/sqlite3.html
  2. https://sqlite.org/autoinc.html
  3. https://sqlite.org/datatype3.html
  4. https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.row_factory

Last modified: 202110020014

Numpy

This is the standard way to import Numpy into your Python project, and it's good practice.

import numpy as np

Arrays

If modifying the array, ensure you make a copy of the array through copy.deepcopy

import numpy as np
import copy
arr = np.array([1,2,3])
a = copy.deepcopy(arr)

Make a multidimensional array

# 3D
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
result = np.array(arr)
# 2D
arr = [ [1,2,3,4], [5,6,7,8], [9,10,11,12] ]
result = np.array(arr)
# 3D
arr = [ [ [1,2], [3,4] ], [ [5,6], [7,8] ], [ [9,10], [11,12] ] ]
result = np.array(arr)

Make a multidimensional array filled with something

# returns a 3x5 2D array filled with '.'s
arr = np.full((3, 5), '.')

Get length of each side

np.size(array_name, axis_number)
print('Axis 0 size : ', np.size(arr3D, 0))
print('Axis 1 size : ', np.size(arr3D, 1))
print('Axis 2 size : ', np.size(arr3D, 2))

Accessing elements

1D Arrays can be accessed via indexing just like an array. 2D and higher use a slightly different syntax.

Axes are represented as (Y, X) in 2 dimensional arrays, as in (row, column).

# 2D
arr = [ [1,2,3,4], [5,6,7,8], [9,10,11,12] ]
element = arr[0,0] # 1
element = arr[1,2] # 7

Iteration

To iterate through every element within the array, going through all dimensions:

import numpy as np
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
for x in np.nditer(arr):
    print(x)

If you want indexes enumerated over also, as a tuple:

for index, x in np.ndenumerate(arr):
    print(index, x)

References:

  1. https://numpy.org/doc/stable/reference/generated/numpy.full.html
  2. https://stackoverflow.com/questions/5891410/numpy-array-initialization-fill-with-identical-values
  3. https://thispointer.com/how-to-get-numpy-array-dimensions-using-numpy-ndarray-shape-numpy-ndarray-size-in-python/
  4. https://www.w3schools.com/python/numpy_array_indexing.asp
  5. https://www.sharpsightlabs.com/blog/numpy-axes-explained/
  6. https://stackoverflow.com/questions/17079279/how-is-axis-indexed-in-numpys-array
  7. https://stackoverflow.com/questions/37593013/deep-copy-of-a-np-array-of-np-array

Last modified: 202107020543

Unittest

unittest is a built-in testing framework for Python.

Getting Started

Create a new file in the same folder as your program called filename.test.py. Import unittest as well as the main program in the test file.

import unittest
import my_program

Once you have these, you can create test cases and unit tests within them. The test cases are subclasses of unittest.TestCase, and the unit tests need to be named test_ followed by whatever naming you want to use. Any method that does not start with test_ will not be run.

setUp and tearDown run at the beginning and end of each unit test. setUpClass and tearDownClass run at the beginning and end of each test case.

class WidgetTestCase(unittest.TestCase):
    def setUpClass()

    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        pass

    def test_default_widget_size(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

    # You can disable tests by using this decorator
    @unittest.skip("reason for skipping") # reason is not necessary
    def test_widget_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

You can run your test suite by running python3 -m unittest in the root directory of the program. This will search for files using unittest within the current directory.

References

Last modified: 202110202006

bash

Basic Functions

  • cp [-r] ./source ./destination - Copy file or directory [-r] from source to destination
  • mv [-r] ./source ./destination - Move/rename file or directory [-r] from source to destination

Background Tasks

You can run tasks in the background within a terminal window by placing an & at the end of the command you want running. You can see these background jobs with jobs and kill the job that you want with kill % followed by the index, or just kill % to kill all jobs.

Event Designators

An event designator is a reference to a command line entry in the history list. Unless the reference is absolute, events are relative to the current position in the history list.

  • $_ Repeat the last argument used, e.g. mkdir folder-name && cd "$_"
  • !! Repeats the previous command
  • !10 Repeat the 10th command from the history
  • !-2 Repeat the 2nd command (from the last) from the history
  • !string Repeat the command that starts with “string” from the history
  • !?string Repeat the command that contains the word “string” from the history
  • ^str1^str2^ Substitute str1 in the previous command with str2 and execute it
  • !!:$ Gets the last argument from the previous command.
  • !string:n Gets the nth argument from the command that starts with “string” from the history.
  • !^ first argument of the previous command
  • !$ last argument of the previous command
  • !* all arguments of the previous command
  • !:2 second argument of the previous command
  • !:2-3 second to third arguments of the previous command
  • !:2-$ second to last arguments of the previous command
  • !:2* second to last arguments of the previous command
  • !:2- second to next to last arguments of the previous command
  • !:0 the command itself

Aliases

WIthin your ~/.bashrc file, add this line and populate it how you need:

alias alias_name="command_to_run"

# e.g.
alias poo="say 'I have to poop really bad'"

When complete, run source ~/.bashrc or source ~/.zshrc and restart bash to have them take effect.

Pipe

To connect the STDOUT of one command to the STDIN of another use the | symbol, commonly known as a pipe.

# long way
$ thing1 > tempfile
$ thing2 < tempfile

# shorter
$ thing1 > tempfile && thing2 < tempfile

# shortest
$ thing1 | thing2

Base64

base64 path/to/file > output.txt will encode whatever file into base64.

echo -n 'some string' | base64 > output.txt will encode a string as input and not encode unusable chars, like line feeds.

The --decode flag may be added to reverse this process.

Troubleshooting

Errors from Windows

If you got a script that looks totally fine but is throwing errors that make very little to no sense, like failing cd and cp, it's probably containing \r from a Windows computer.

tr -d "\r" < oldname.sh > newname.sh

References

  1. https://www.serverlab.ca/tutorials/linux/administration-linux/how-to-base64-encode-and-decode-from-command-line/
  2. https://linuxize.com/post/how-to-create-bash-aliases/
  3. https://askubuntu.com/questions/172982/what-is-the-difference-between-redirection-and-pipe/172989#172989?newreg=cfc8024a2d4b40daa24578e47df2b7cf
  4. https://stackoverflow.com/a/11428439
  5. https://unix.stackexchange.com/questions/19654/how-do-i-change-the-extension-of-multiple-files
  6. https://mywiki.wooledge.org/BashFAQ/030
  7. https://devhints.io/bash
Backlinks

Last modified: 202110010324

Python with Bash

This is how to utilize piping with Python programs in Bash.

Example

See this simple echo.py:

import sys

if __name__ == "__main__":
    for line in sys.stdin:
        sys.stderr.write("DEBUG: got line: " + line)
        sys.stdout.write(line)

running:

$ ls | python echo.py 2>debug_output.txt | sort

output:

echo.py
test.py
test.sh

debug_output.txt content:

DEBUG: got line: echo.py
DEBUG: got line: test.py
DEBUG: got line: test.sh

References

  1. https://stackoverflow.com/questions/4429966/how-to-make-a-python-script-pipeable-in-bash

Last modified: 202110010327

Math (Python)

Get Quotient and Remainder

divmod returns a tuple of the quotient and the remainder/modulo.

divmod(20, 3) # (6, 2)

Round Decimals

The round function in Python allows you to round your decimal. The arguments taken are:

# round(number, decimal_places)
round(3.1415926, 3)  # 3.142

References

  1. https://tutorialdeep.com/knowhow/round-float-to-2-decimal-places-python/

Last modified: 202107020542

JSON (Python)

Load JSON from file

def load_json(fp):
    with open(fp, 'r') as f:
        output = json.load(f)
    return output

Save to JSON file

def save_json(fp):
    with open(fp, 'w') as f:
        # with pretty output kwargs
        json.dump(sample, f, indent=4, sort_keys=True)

References:

  1. https://docs.python.org/3/library/json.html
  2. Python

Last modified: 202107020542

Cube CSS

Cube CSS is a CSS framework that is composition first and values it above everything else. The thesis is that when things work together and have a harmony between their design and structure, the amount of work that will need to be done later will be minimal.

Base CSS

These are all of your resets ((removing margins, list styles, setting default image width, etc.) and basic choices that will apply to all of your HTML.

Composition

This is where the bulk of your stylistic choices will be made and they will be made as classes that will be applied.

Utilities

Block

Exception

References

  1. https://every-layout.dev/layouts/stack/
  2. https://alistapart.com/article/axiomatic-css-and-lobotomized-owls/
  3. https://every-layout.dev/rudiments/modular-scale/
  4. https://issue33.com/
  5. https://github.com/hankchizljaw/modern-css-reset

Last modified: 202107020522

Selectors (CSS)

Selectors are the backbone of CSS, allowing the developer to create stylesheets that apply and cascade to many elements at a time.

Selectors

  • type
  • #id
  • .class
  • [attribute] - Select all elements with attribute
    • [attribute="X"] - Select elements with attribute of value 'X' (e.g. attribute="X")
    • [attribute~="X"] - Select elements with an attribute that contains value 'X' (e.g. attribute="W X Y Z")
    • [attribute*="X"] - Select elements with an attribute that contains substring 'X' (e.g. attribute="WXYZ")
    • [attribute^="X"] - Select elements with attribute that starts with 'X' (e.g. attribute="XYZ ABC" but not "ABC XYZ")
    • [attribute|="X"] - Select elements with attribute that has value 'X' or begins with 'X-' (e.g. attribute="X-YZ")
    • [attribute$="X"] - Select elements with attribute that ends with 'X' (e.g. attribute="VWX")
    • [... i] - Make selection of the quoted value case insensitive
  • A B - Select all elements B that are inside of A
  • A + B - Select all elements B that are adjacent to and come directly after A
  • A ~ B - Select all elements B that are adjacent to and come after A at some pont
  • A > B - Select all elements B that are direct children of A

Pseudoclasses

Pseudoclasses are prefaced by a single colon.

Parent

  • A:empty - Select element A if they have no child elements

Child

  • A:first-child
  • A:last-child
  • A:nth-child(n)
  • A:nth-last-child(n) - Select every nth element of A counting from the last element to the first
  • A:only-child - Select element A if they are the only child element of their parent element
  • B A:only-child - Select element A if they are the only child element of parent element B

Type

  • A:first-of-type - Select the first element of type A
  • A:nth-of-type(n/even/odd) - Select the nth element of type A or every even or odd numbered instance of element of type A
  • A:nth-of-type(Nn+X) - Select every Nth element of A starting on and including offset X (e.g. A:nth-of-type(2n+3) will select every odd element starting on element 3)
  • A:only-of-type - Select A if it is the only child of that type
  • A:last-of-type - Select the last of element type A

State

Links

  • A:link - Select A if it is an anchor element
  • A:visited
  • A:hover
  • A:active - Select A if it has been selected

a:hover MUST come after a:link and a:visited in the CSS definition in order to be effective. a:active MUST come after a:hover in the CSS definition in order to be effective. "LoVe, HAte"

If you want to select an element when hovering over an element:

.parent-selector:hover .child-selector { ... } /* Child */
.parent-selector:hover + .sibling-selector { ... } /* Sibling */
/* etc. */

Forms and Inputs

  • A:focus - Select A if it currently has focus (e.g. text input when selected)
  • A:invalid - Select A if it currently has an invalid entry (e.g. not matching the pattern)
  • A:focus:invalid - Select A if it has focus and has an invalid entry
  • A:placeholder-shown - Select A if the placeholder is being shown

Anchor/URL Hash

  • A:target - Select A if the #id of A is the suffix of the URL.
/* <div id="cool-thing" class="thing"></div> */
/* if URL is index.html#cool-thing, put border around the div with id "cool-thing" */

.thing:target {
  border: 10px solid red;
}

Meta

  • A:not('X') - Select all A elements if they do not match selector or pseudoclass X (e.g. #id, .class, :last-child, etc.)

Pseudoelements

Pseudoelements are prefaced by two colons.

  • A::placeholder - Select the placeholder within element A (e.g. placeholder text of a text input box)
  • A::first-line - Select the first line of a block element.
  • A::first-letter - Select the first letter of an element.

Content

The ::before and ::after pseudoclasses allow you to place content before or after the selection. They require a content property and a display property. These pseudoclasses are treated like children of the selected element. e.g. 100% width is 100% width of the selected element.

.selector::after {
  content: "";
  display: inline-block;
  height: 100%;          /* same width/height as parent */
  width: 100%;
  border-radius: 100px;
  position: absolute;
  top: 0;                /* same position as parent */
  left: 0;
  z-index: -1;
}

References

  1. https://www.w3schools.com/cssref/css_selectors.asp
  2. https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
Backlinks

Last modified: 202107020516

Transitions (CSS)

Transitions allow you to transform a CSS rule from one set of values to another, and can be triggered either by a pseudoclass selector, on a regular cycle, or just once when loaded.

This example I modified from MDN shows how you would transform the background color of a button on hover:

#button {
  background-color: rgba(0, 2, 143, 1);
  transition-property: background-color;
  transition-duration: 4s;
  transition-timing-function: ease;
  transition-delay: 2s;
}

#button:hover {
  background-color: rgba(0, 2, 143, 0.5);
}

References:

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions

Last modified: 202107020518

Minimalist CSS

This CSS code makes really beautiful text-centric websites that are responsive and look nice with only like 54 bytes or something? I use this as a basis all the time for making nice looking pages.

main {
  max-width: 38rem;
  padding: 2rem;
  margin: auto;
}

References

  1. https://jrl.ninja/etc/1/

Last modified: 202107020511

Fonts (CSS)

Importing and using external fonts properly in CSS.

Using @font-face

@font-face {
  font-family: 'Verlag Condensed Bold';
  src: url('https://brandlive-upload.s3-us-west-2.amazonaws.com/933/documents/1wp6lcexy4/verlagcondensedbold.otf');
  [ unicode-range: <unicode-range>; ] ||
  [ font-variant: <font-variant>; ] ||
  [ font-feature-settings: <font-feature-settings>; ] ||
  [ font-variation-settings: <font-variation-settings>; ] ||
  [ font-stretch: <font-stretch>; ] ||
  font-weight: bold;
  [ font-style: <font-style>; ]
}

You can include multiple src values via a call to the user's fonts via local("Font Name"), url("..."), as well as specifying formats after the url (url("...") format("truetype"),), all separated by commas and ending with a semicolon.

@import vs. <link>

To bring in another stylesheet with a font attached, Google Fonts and others offer an @import option. This unfortunately is blocking and and will delay all other loading until that import is complete. Instead, include the url in a <link> and it will load all elements at the same time.

<link href='http://fonts.googleapis.com/css?family=Judson:400,400italic,700' rel='stylesheet' type='text/css'>

References

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face

Last modified: 202107020507

Sass

Sass is a CSS preprocessor that allows a lot more ease in maintainability and gives much deeper modularity than CSS normally provides. Sass is a language that compiles into CSS, most often used in it's .scss variant, as it is much more similar to normal CSS than its counterpart (.sass).

Setup/Meta

Install Sass

On Mac, use brew install sass/sass/sass to install the newest version of Sass on your machine.

Command Line Options

  • path/to/input.scss:path/to/output.css - Compile the input file to output file
  • path/to/inputfiles/:path/to/outputfiles/ - Compile any SCSS files within input directory to output directory as CSS
  • --watch path/to/input.scss:path/to/output.css - Continuously watch the input file and compile it on change to output file
  • --watch path/to/inputfiles/:path/to/outputfiles/ - Continuously watch the input directory and compile any SCSS files within to output directory as CSS on change
  • -v - Output the current version that is being run
  • --sourcemap=none / --no-source-map - Don't output a source map on compile (former for Ruby Sass, latter for Dart Sass

Syntax

Comments

Comments are done using the standard Javascript syntax: // and /* */ for multiline.

Variables

Variables, like --variable in CSS3, are done by prepending the variable name with a dollar sign

$variable-name: value;

When variables are used in a calc function, the variable needs to be surrounded by #{ }.

width: calc(100% - #{$variable});

Nesting

Instead of writing many specific selectors, you can use nesting to enclose selectors that are children of other selectors. Using an ampersand before a nested selector will write out the selector that is in use at that point in its place when compiled.

Nesting is extremely useful in BEM, as the otherwise long and ugly class names become much more easy to read and navigate. In Sass, the & is shorthand for the entire selector at that point.

// bad
.block { ... }
.block--modifier { ... }
.block__element { ... }
.block__element:hover { ... }
.block__element--modifier { ... }

// good
.block {
  ...

  &--modifier {  // & === `.block`
    ...
  }

  &__element {
    ...

    &:hover {
      ...
    }

    &--modifier {
      ...
    }
  }
}

Mixins

Mixins are a group of declarations or rules that can be reused throughout by copying their contents into a rule. They can also include parameters for dynamic value generation. The mixin is defined by using @mixin and then called with @includes and the name.

NOTE: You have to @import (not @use) the mixin partial to every file that uses it.

// with mixin using parameters
@mixin box-shadow($x, $y, $blur, $c){
 -webkit-box-shadow: $x $y $blur $c;
    -moz-box-shadow: $x $y $blur $c;
     -ms-box-shadow: $x $y $blur $c;
         box-shadow: $x $y $blur $c;
}

Another file:

@import 'path/to/mixin';

div {
 @include box-shadow(0px, 0px, 4px, #fff);
}

// compiled result
div {
 -webkit-box-shadow: 0px 0px 4px #fff;
    -moz-box-shadow: 0px 0px 4px #fff;
     -ms-box-shadow: 0px 0px 4px #fff;
         box-shadow: 0px 0px 4px #fff;
}

Functions

Functions are created by using @function with a name and a parameter list. Inside the function, a @return is required. It is common when a raw number is returned to multiply it by 1 * unit, with unit being px, em, etc.

@function divide($a, $b) {
  @return $a / $b;
}

// called
p {
  margin: divide(60, 2) * 1px;
}

Conditionals

@if, @else if, and @else are what they sound like and are used within a mixin.

@mixin make-bold($bool) {
  @if $bool == true {
    font-weight: bold;
  }
}

@mixin text-effect($val) {
  @if $val == danger {
    color: red;
  }
  @else if $val == alert {
    color: yellow;
  }
  @else if $val == success {
    color: green;
  }
  @else {
    color: black;
  }
}

Iteration

For loops including the last number, use through. For loops excluding the last number, use to.

@for $i from 1 through 12 {
  .col-#{$i} { width: 100%/12 * $i; }
}

@for $i from 1 to 13 {
  .col-#{$i} { width: 100%/12 * $i; }
}

For each loops are done with @each.

@each $color in blue, red, green {
  .#{$color}-text {color: $color;}
}

//alternative
$colors: (color1: blue, color2: red, color3: green);
@each $key, $color in $colors {
  .#{$color}-text {color: $color;}
}

While loops are done with @while.

$x: 1;  /* define variable `x` as 1 */
@while $x < 13 {
  .col-#{$x} { width: 100%/12 * $x;}
  $x: $x + 1;
}

Imports/Partials

You can create separate stylesheets and import them in to your main sheet.

Partials are what will be imported into the main sheet. These filenames start with an underscore and end with .scss.

Depending on the version of Sass that is being used, they use @import or @use followed by the partial enclosed in single quotes without the underscore or the extension. (@import is being phased out, so if you can, use @use)

// partial file is at fp "./base/_base.scss"

// if using Dart Sass:
@use 'base/base';
// else
@import 'base/base';

https://www.freecodecamp.org/learn/front-end-libraries/sass/split-your-styles-into-smaller-chunks-with-partials

Extending Rules

Rules can be extended from one element to another one through copying the rules and then further modification (header -> small-header). @extend followed by the original selector. Extend can also be used on a placeholder rule, defined by using a preceding %.

Extensions should be used only when the elements it is extending are inherently and thematically related, but extend is generally not advised because you will be "distributing selectors across [your] codebase for purely circumstantial reasons", leading to bloated and difficult to maintain code.

The difference between this and a mixin is instead of bringing code into another rule, we are bringing the selectors that include the extend command to the rule.

%panel {
  background-color: red;
  height: 70px;
  border: 2px solid green;
}

.big-panel {
  @extend %panel;
  width: 150px;
  font-size: 2em;
}

.long-panel {
  @extend %panel;
  width: 1000px;
}

// compiled result
.big-panel,
.long-panel {
  background-color: red;
  height: 70px;
  border: 2px solid green;
}

.big-panel {
  width: 150px;
  font-size: 2em;
}

.long-panel {
  width: 1000px;
}

References

  1. https://www.udemy.com/course/advanced-css-and-sass
  2. https://www.freecodecamp.org/learn/front-end-libraries/sass/
  3. https://sass-lang.com/documentation/at-rules/import
  4. https://sass-lang.com/documentation/at-rules/use
  5. https://sass-lang.com/guide
Backlinks

Last modified: 202109161631

Inverted Triangle CSS

ITCSS is a way to structure your CSS projects to minimize specificty issues and organizational problems. ITCSS is not a naming convention.

ITCSS is most effective when used with a preprocessor like Sass, Less, etc.

Principles

The inverted triangle refers to how your CSS project should be put together. At the beginning, we have the most far-reaching, least specific, and most generic styles possible. This includes variables, sitewide styles like font-settings, and CSS resets. As we go farther in the file, we get more localized, more specific, and more explicit styles. This includes component-specific styles and rules.

Layers

The inverted triangle has layers from top to bottom, representing the amount of reach each layer should have; the first layers have the most, decreasing their reach the farther down you go.

The first two layers should not generate any CSS on their own if being used with a preprocessor.

  1. Settings - Variables
  2. Tools - Any mixins or functions that need to be globally available. If they don''t need to be globally available, they should go somewhere else.
  3. Generic - Includes Normalize, resets, box-sizing rules, etc.
  4. Elements - These are the styles that refer to unclassed HTML elements. Changing the font-size of headings, the focus styles on inputs, or default anchor and link behavior.
  5. Objects - Undecorated design patterns, like wrappers, containers, rows, grids, etc.
  6. Components - Specific UI components. Most of our styling should go here, as most UI components should be composed of objects and components.
  7. Utilities (Trumps) - Anything that should be able to override the previous styles.

BEMIT

This framework can be combined with BEM to make the HTML more readable for the developer. Using the standard Block, Element (__), Modifier (--) syntax, we can also use prefixes and suffixes to make their functionality more clear.

Prefixes

  • o- - Object
  • c- - Component
  • u- - Utility/Trump
  • is-/has- - State
  • js- - Javascript hook
  • _ - Outright hacks

Suffixes

  • @ - Responsive media or print queries (need to escape @ in CSS with \@)

References

  1. https://www.freecodecamp.org/news/managing-large-s-css-projects-using-the-inverted-triangle-architecture-3c03e4b1e6df/
  2. https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/
  3. http://www.jamesturneronline.net/blog/bemit-naming-convention.html

Last modified: 202107020524

Object Oriented CSS

Another CSS framework

Main Principles

  1. Separate structure and skin - Structure and position declarations should be in the base object (along with default visual declarations if necessary), while any visual declarations should go into extender classes.
  2. Separate container and content - Break the dependency between the container module and the content objects in contains

More Best Practices

  1. Create a component library - Make components (legos) with which you can build your site. These components could include headers, lists, media components, etc. Build these before building your site.
  2. Extend objects by applying multiple classes to an element - Don't make one class do everything. Utilities, modifiers, and base classes can combine to make a much easier to maintain style.
  3. Minimize selectors - Low specificity means less cascade problems and runaway specificity races.
  4. Use consistent semantic styles
  5. Design modules to be transparent on the inside
  6. Be flexible - Height and width should be able to adapt themselves and should not rely on constant babysitting by the designer/developer.
  7. Learn to love grids

9 Pitfalls

  1. Avoid location dependent styles - You want your code to be modular. If it only works if it is in a certain context or position, it is not modular and prone to breakage.
  2. Avoid specifying what tag a class applies - A 'heading' should do something predictable from page to page.
  3. Avoid IDs - They add unnecessary specificity errors and can only be used once, so are needlessly specific.
  4. Avoid drop shadows and rounded corners over irregular backgrounds - This may cause undesired results
  5. Avoid height alignment - Height should be defined by the content of the element. Instead of this, ensure you are separating the container from the content.
  6. Don't use images as text - Screen readers and users on older software often rely on text only and this will make pages needlessly difficult to use.
  7. Avoid redundancy - If two components look too similar to be used on the same page, they are too similar to use on the same site. Choose one!
  8. Avoid premature optimization - If you are unsure what is the best choice, do the naive solution first, and then refactor afterwards.
  9. Don't sprite every image together, unless you have very few pages (seems like dated advice at this point)

Grids control width, content controls height

References

  1. https://www.slideshare.net/stubbornella/object-oriented-css/37-Avoid_redundancy
  2. https://www.benmarshall.me/oocss-object-oriented-css/
  3. https://www.slideshare.net/stubbornella/our-best-practices-are-killing-us

Last modified: 202107020525

Vendor Prefixes (CSS)

Vendor prefixes are used to ensure that older or unsupported browsers have every possibility of implementing the desired rule. Vendor prefixes are before the declarations and denote which tech/browser/setup it is intended for.

div {
  -webkit-box-shadow: 0px 0px 4px #fff;
     -moz-box-shadow: 0px 0px 4px #fff;
      -ms-box-shadow: 0px 0px 4px #fff;
          box-shadow: 0px 0px 4px #fff;
}

Using Sass

Sass mixins allow browser prefixes to be done easily.

Using Autoprefixer

You can run Autoprefixer on your CSS to add the prefixes needed on your completed CSS.

Do I have to?

Find out if you do here:

References

  1. https://css-tricks.com/snippets/sass/mixin-prefix-properties/
Backlinks

Last modified: 202107020520

Typography (CSS)

How to properly define and apply typography rules in CSS.

Line Height

The normal value on a line-height property in CSS is calculated as 1.2x the font size; e.g. a font size of 16px will have a normal line height of (1.2 * 16)px = 19.2px.

When setting a defined line-height, use the em unit to set it relative to the current font-size.

Best Practices

1.5em is the most common line height for copy.

  • The longer the line length, the taller the Line-height should be.
  • The shorter the line length, the shorter the Line-height should be.
  • Use a taller line-height with continuous copy.
  • Use taller line-heights with large x-height fonts.
  • The ascenders and descenders of the lines of text should not touch.
  • Place the lines close enough together that the reader requires no effort to find the next line, then balance the height based on the line length.

References

  1. http://smad.jmu.edu/shen/webtype/lineheight.html
  2. https://www.madebymike.com.au/writing/precise-control-responsive-typography/
  3. https://blog.typekit.com/2016/08/17/flexible-typography-with-css-locks/

Last modified: 202107020519

Alignment (CSS)

Block Elements

To horizontally center a block element with a width other than 100%, use margin: auto;. Setting the width of the element will prevent it from stretching out to the edges of its container. The element will then take up the specified width, and the remaining space will be split equally between the two margins.

Inline and Inline-Block Elements

Horizontal alignment can be done using text-align: center;.

To align text vertically, however, the vertical-align property is used. The vertical-align property works only with inline and table-cell elements — it won’t work for block, inline-block, or any other element levels. The vertical-align property accepts a handful of different values; the most popular values are top, middle, and bottom. These values vertically position text in relation to the table cell, for table-cell elements, or to the closest parent element, for inline-level elements.

Image/Icon/Font Awesome Alignment

Although the text needs to be aligned with the image, it is actually the image that needs to be aligned and the text will move accordingly.

<style>
  .icon {
    vertical-align: middle;
  }
</style>

<span>Some text <img class="icon" src="..."></span> <!-- or ... -->
<span>Some text <i class="icon fa ..."></i></span>

Using 100vh/100vw

100vh and 100vw won't work as expectedunless you set the margin and padding of the selected element to 0.

References

  1. https://css-tricks.com/centering-css-complete-guide/
  2. https://learn.shayhowe.com/html-css/organizing-data-with-tables/
  3. https://stackoverflow.com/questions/17309928/how-to-center-text-vertically-with-a-large-font-awesome-icon

Last modified: 202107020504

Position (CSS)

The position property in CSS gives the developer control over the x-, y-, and z-axis in aligning elements.

  • static - This is the default position that a property will have if left unset. The equivalent of being unpositioned. This element will be in the standard flow of the document. This value is the only value that will not create a new stacking context (z-axis).
  • relative - A relatively positioned element will be in the standard flow of the document, but can be positioned relative to its current position (e.g. top, left, bottom, right). This offset doesn't affect other elements in flow. Space will still exist in flow for this element in it's original position, even if it is moved. relative can create a new stacking context if the z-index is not set to auto.
  • absolute - An absolutely positioned element will be out of the regular flow of the document and can be positioned according to the closest positioned (not static) parent element. No space will be made for it in the document. This can create a new stacking context if the z-index is not set to auto.
  • fixed - Like absolute, a fixed element will be removed from the standard flow and no space will be made. This will be positioned according to the box created by the browser's viewport. This will always create a new stacking context and will print on every document when printed.
  • sticky - This is positioned in a normal flow of a document, like relative, and then offset to it's nearest scrolling relative (i.e. has an overflow property set to a scrolling value). This will also always create a new stacking context.

References

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/position

Last modified: 202107020513

Color Palettes (CSS)

https://monokai.pro/

:root {
  --red:    #ff6188;
  --orange: #fc9867;
  --yellow: #ffd866;
  --green:  #a9dc76;
  --blue:   #78dce8;
  --purple: #ab9df2;

  --white:  #fdf9f3;
  --gray:   #bcbbbb;
  --black:  #2c292d;
}

https://github.com/mrmrs/colors

/* 
   VARIABLES
   - Cool
   - Warm
   - Gray Scale
*/

:root {
  --aqua:  #7FDBFF;
  --blue:  #0074D9;
  --navy:  #001F3F;
  --teal:  #39CCCC;
  --green: #2ECC40;
  --olive: #3D9970;
  --lime:  #01FF70;

  --yellow:  #FFDC00;
  --orange:  #FF851B;
  --red:     #FF4136;
  --fuchsia: #F012BE;
  --purple:  #B10DC9;
  --maroon:  #85144B;

  --white:  #FFFFFF;
  --silver: #DDDDDD;
  --gray:   #AAAAAA;
  --black:  #111111;
}

Windows 3.1

/* 
   VARIABLES:
   - Dark
   - Bright
   - Grayscale
*/

:root {
  --dark-red:    #7e0000; /* maroon */
  --dark-yellow: #7e7e00; /* olive */
  --dark-green:  #047e00; /* plant green */
  --dark-cyan: #047e7e; /* teal */
  --dark-blue:   #00007e; /* navy blue */
  --dark-purple: #7e007e; /* plum */

  --red:    #fe0000;
  --yellow: #ffff04;
  --green:  #06ff04; /* neon green */
  --cyan:   #06ffff; /* aqua */
  --blue:   #0000ff;
  --purple: #fe00ff; /* fuschia */

  --white:     #000000;
  --gray:      #7e7e7e;
  --dark-gray: #bebebe;
  --black:     #ffffff;
}

Original VGA

/* 
   VARIABLES:
   - Dark
   - Bright
   - Grayscale
*/

:root {
  --dark-red:    #aa0000; /* candy apple */
  --dark-orange: #aa5500; /* tan */
  --dark-green:  #00aa00; /* grass */
  --dark-cyan:    #00aaaa; /* tiffany blue */
  --dark-blue:   #0000aa; /* deep blue */
  --dark-purple: #aa00aa; /* magenta */

  --red:    #ff5555; /* coral */
  --yellow: #ffff55; /* daffodil */
  --green:  #55ff55; /* slime */
  --cyan:   #55ffff; /* cyan */
  --blue:   #5555ff; /* light blue */
  --purple: #ff55ff; /* pink */

  --white:      #ffffff;
  --gray-light: #aaaaaa;
  --gray-dark:   #555555;
  --black:      #000000;
}

Colorblindness Colors

https://jfly.uni-koeln.de/color/#pallet

From their page:

This is a proposal of color pallet that is 1: unambiguous both to colorblinds and non-colorblinds, 2: with vivid colors so that color names are easy to identify, 3: can be printable with similar color both on screen and when printed.

  • For red, vermilion is used since it is recognizable also to protanopes.

  • Colors between yellow and green are all avoided, since they are indistinguishable with yellow and orange.

  • For green, bluish green is chosen so that it won't be confused with red or brown.

  • Since violet is close to blue and appear the same to colorblinds, reddish purple is chosen.

  • Between vermilion and yellow, three colors with different apparent intensity is selected.

  • Sky blue and blue are chosen so that they are distinguishable with there difference in brightness and saturation.

  • Even for non-coloblinds, thin lines and small characters in blue and yellow are hard read. For thin lines and small objects, use darker blue and orange is preferable to sky blue and yellow.

When combining colors from this pallet,

  • Use "warm" and "cool" colors alternatively.
  • When using two warm colors or two cool colors, put distinct differences in brightness or saturation.
  • Avoid combination of colors with low saturation or low brightness.
/* 
   VARIABLES:
   - Dark
   - Bright
   - Grayscale
*/

:root {
  --black: rgba(0,0,0);
  --orange: rgba(230,159,0);
  --sky-blue: rgba(86,180,233);
  --bluish-green: rgba(0, 158, 115);
  --yellow: rgba(240,228,66);
  --blue: rgba(0,114,178);
  --vermillion: rgba(213,94,0);
  --reddish-purple: rgba(204,121,167);
}

Misc Colorsets

https://lospec.com/palette-list/1bit-monitor-glow

  --black: #222323;
  --white: #f0f6f0;

TI Calculators

  --black: #1E1F1A;
  --white: #b7b9ab;

Toshiba 3200

  --black: #600D00;
  --dark-gray: #b81903;
  --gray: #da3f1b;
  --white: #fe591f;

Gameboy

  --black:     #081820;
  --dark-gray: #346856;
  --gray:      #88c070;
  --white:     #e0f8d0;

Last modified: 202107020505

Text Selections (CSS)

How to use CSS to give or take away the user's ability to select text on a page.

Disable

Particularly with span or div style buttons that can be clicked a bunch and end up with their text selected.

.disable-select{
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}

Select All

This allows all the inner text to be copied when clicking inside the selected element.

.copy-all-text{  
  -webkit-user-select: all;  /* Chrome all / Safari all */
     -moz-user-select: all;  /* Firefox all */
      -ms-user-select: all;  /* IE 10+ */
          user-select: all;  /* Likely future */   
}

References

  1. https://www.freakyjolly.com/how-to-disable-text-selection-highlighting/

Last modified: 202107020517

Organization and Structure (CSS)

Miscellaneous notes and best practices on organization and structure in CSS.

Best Practices

Keep it consistent

If you get to set the rules for the project or are working alone, then the most important thing to do is to keep things consistent. Consistency can be applied in all sorts of ways, such as using the same naming conventions for classes, choosing one method of describing color, or maintaining consistent formatting (for example will you use tabs or spaces to indent your code? If spaces, how many spaces?)

If you are working with a team on an existing project, the first thing to check is whether the project has an existing style guide for CSS. The team style guide should always win over your own personal preferences. There often isn't a right or wrong way to do things, but consistency is important.

Organize Code with Comments

Adding comments to your CSS will help any future developer work with your CSS file, but will also help you when you come back to the project after a break. A good tip is to add a block of comments between logical sections in your stylesheet too, to help locate different sections quickly when scanning through, or even give you something to search for to jump right into that part of the CSS. If you use a string which won't appear in the code you can jump from section to section by searching for it.

/* || General Styles */
...
/* || Utilities */

Build Proficient Selectors

Don't use IDs in your selectors. This messes with the specificity and often breaks cascades. In general, in seems like it's best practice to stick with classes as your selectors.

Keep selectors short, since the longer they get, the more apt they are to break. If you create very specific selectors you will often find that you need to duplicate chunks of your CSS to apply the same rules to another element. Try to reduce nesting to two or three levels deep and remove as many location-based selectors as possible. Usually, these longer selectors are overkill and unnecessary. If you do find that you need to use a really specific selector, refactor it into a new manageable class.

Use Shorthand Properties & Values

Do this to increase readability. If your shorthand font: property is not more readable, then it is not better. Shorthand properties can also introduce undesired resetting of properties (sometimes unrelated) back to their initial value.

/* bulky, but clear */
p {
  font-family: sans-serif;
  font-size: 1.6rem;
  font-style: italic;
  font-weight: 400;
  line-height: 1.5;
}

/* cleaner, but not necessarily clearer */
p {
  font: sans-serif 1.6rem italic 400 1.5;
}

Drop Units from Zero Values

/* BAD */
margin: 0px 10px 0px 0px;
/* GOOD */
margin: 0 10px 0 0;

Use The Right Measurement For The Right Job

I have read many different pieces of advice on this. Use rem for everything, use em for everything, don't use px ever, use 60ch as the width of a page, etc. I do believe that using rem for everything may cause blowout of a page when zooming in a lot for accessibility, due to enormous borders, margin, etc. This is some advice I found online that seems to make sense:

  • px for border widths, box shadows, etc. (decoration)
  • rem or em for font sizes (rem for modular component-based layouts)
  • vw/vh/% for layout and display specific rules, since they change with the browser size
  • rem for font sizes and for margins and padding
  • ch for things like paragraph text widths or sizing containers that will hold monospace fonts (50-70 chars wide is a common human-readable width, so aim for 60ch in this case)
  • em for media queries (e.g. max-width: 40em is equal to 640px with a font-size of 16px, but will scale if user has it set differently)
  • in/cm/mm for print queries

Group & Align Vendor Prefixes

Keep them together and add whitespace to make the values aligned.

When using vendor prefixes we need to make sure to place an unprefixed version of our property and value last, after any prefixed versions, to ensure the most desired setting loads last if possible.

div {
  background: -webkit-linear-gradient(#a1d3b0, #f6f1d3);
  background:    -moz-linear-gradient(#a1d3b0, #f6f1d3);
  background:         linear-gradient(#a1d3b0, #f6f1d3);
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

Modularize Styles for Reuse

Refactor names to fit their purpose and reduce hacky "fixes" to shoehorn stuff in to other class rules. Keep your code DRY!

Break large stylesheets into multiple smaller ones

In particular in cases where you have very different styles for distinct parts of the site, you might want to have a stylesheet that includes all the global rules and then smaller ones that include the specific rules needed for those sections. You can link to multiple stylesheets from one page, and the normal rules of the cascade apply, with rules in stylesheets linked later coming after rules in stylesheets linked earlier.

Structure / Formatting

Create logical sections in your stylesheet

Using the ideas from 7-1 Sass architecture, we can create an organization that will allow us to organize our styles in a way that allows for a logical hierarchical cascade and easy management. The 7 sections are abstracts, vendors, base, layout, components, pages, and themes.

Media Queries

Note: media queries don't have an exact space so far as I have found, but there are a couple approaches:

  • for maintenance and modularity's sake, keeping them with the rest of the relevant rules feels logical.
  • for the cascade, putting them at the end of their respective file before the utilities allows them to take priority over rules with similar specificity.
.grid { 
  ...
}

@media (screen) and (max-width: 800px) {
  .grid {
    ...
  }
}

Abstracts

Abstracts are code that does not output CSS (variables, and in Sass, functions and mixins).

/* || VARIABLES */

:root {
  --bg-color: #FFF;
  --text-color-primary: #000;
  --text-color-secondary: #888;
  --link-color: #F00;

  --font-sans: Helvetica, sans-serif;
  --font-serif: Times, sans-serif;

  --text-spacing-wide: .5px;
}

Vendors

This includes any third party stylesheets, like Bootstrap, or font imports like Google Fonts.

/* || VENDORS */

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap');

Base

Basic definitions like animations, default styles, typography, resets/normalizers and utilities like classes for center text, margin bottom, etc. It is a good idea to have all of the common styling early in the stylesheet so that all of these styles will generally apply unless you do something special with that element.

/* || BASE STYLES */

/* | RESETS */

html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
}

/* | ANIMATIONS */

@keyframes animationName {
  ...
}

/* | TYPOGRAPHY */

html {
  color: var(--text-color-primary);
  font-family: Helvetica, sans-serif;
}

h1, h2, h3, h4 { 
  ... 
}

a {
  ...
}

/* | UTILITIES */

.nobullets {
  list-style: none;
  margin: 0;
  padding: 0;
}

Layout

This could have styles for the main parts of the site (header, footer, navigation, sidebar, etc.), the grid system, or even CSS styles for all the forms. These are the "macro" components.

/* || LAYOUT */

/* | HEADER */

.header {
  ...
}

/* | FOOTER */

.footer {
  ...
}

/* | GRID */

.grid {
  ...
}

Components

Modules that will be reused often throughout the project (buttons, forms, media boxes, etc.). These are the "micro" components in comparison to the layout.

/* || COMPONENTS */

/* | BUTTON */

.button {
  ...
}

  .button--white {
    ...
  }

  .button--magenta {
    ...
  }

Page

These are styles specific only to the specific page you are on. Many times a home page will have different layouts than the blog or the about page. This is where you would put the styles for that specific page.

For a single stylesheet, this will likely be just another section as opposed to another file.

Theme

For large projects, this allows a plug-and-play way to change the theme of your site. Usually this is not used on smaller applications.

Example CSS Skeleton / Template

/* || ABSTRACTS */

/* || VENDORS */

/* || BASE */

/* || LAYOUT */

/* || COMPONENTS */

/* || PAGES */

/* || THEMES */

References

  1. https://learn.shayhowe.com/html-css/writing-your-best-code/
  2. https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Organizing
  3. https://www.reddit.com/r/css/comments/kzkthl/what_units_do_you_use_px_vw_and_vh_em_rem/
  4. https://meyerweb.com/eric/thoughts/2018/06/28/what-is-the-css-ch-unit/
  5. https://github.com/HugoGiraudel/sass-boilerplate/tree/master/stylesheets
  6. https://www.learnhowtoprogram.com/user-interfaces/building-layouts-preprocessors/7-1-sass-architecture
  7. https://www.freecodecamp.org/news/css-media-queries-breakpoints-media-types-standard-resolutions-and-more/

Last modified: 202107020528

Gradients (CSS)

How to create and use linear gradients in CSS.

Background or Image

/*
linear-gradient(
  {direction},                      `to left top`, `45deg`, `0.25turn`
  {starting color}
    {full color starting position}  `0`, `33%`
    {full color ending position},   `33%`, `50%`
  ...more colors
) 
*/

.gradient {
  background-image: linear-gradient(to right, $color-primary-light, $color-primary-dark);
}

You can make an immediate switch between colors by setting starting and ending positions at the same value. This example goes to the bottom right from 0%-50% with white and then from 50% to 100% with orange.

.selector {
  background-image: linear-gradient(to right bottom, white 50%, orange 50%);
}

Text

h1.gradient-text {
  /* Create the bg gradient */
  background-image: linear-gradient(to right, $color-primary-light, $color-primary-dark);
  /* Confine gradient area to width of content */
  display: inline-block;
  /* Clip the bg gradient to the text area */
  -webkit-background-clip: text;
          background-clip: text;
  /* Allow gradient to show through text area */
  color: transparent;
}

References

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient()

Last modified: 202107020508

zsh

Zsh is a Unix shell based on the Bourne shell, like bash.

Installation

Use homebrew to install Zsh:

$ brew install zsh

To set it as your default shell:

$ sudo sh -c "echo $(which zsh) >> /etc/shells" && chsh -s $(which zsh)

Oh My Zsh

Oh My Zsh is a delightful, open source, community-driven framework for managing your Zsh configuration.

Installation

To install, use this:

$ curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh

Plugins

Plugins are installed using Oh My Zsh and the ~/.zshrc file.

  • z: "Zsh-z is a command line tool that allows you to jump quickly to directories that you have visited frequently in the past, or recently -- but most often a combination of the two (a concept known as "frecency"). It works by keeping track of when you go to directories and how much time you spend in them."

Preinstalled

References

Last modified: 202110232329

Assembly

Assembly is an extremely low-level human-readable language that has a strong relation between the code and the corresponding machine code.

If you are just getting started with assembly, I highly recommend you get started by first checking out the paper computing page to get familiar with the foundations and fundamentals of assembly language.

Compilation and Linking

For more specifics, visit the OSX and Windows assembly pages.

You will first need a program to compile your assembly into machine code. Most common is the program nasm for Unix systems and masm for Windows systems.

After you have written your code, you will need to assemble your code, translating it from the human readable assembly language into a file object.

You will then need to link your newly created output file. This will pull all the needed libraries into a single executable.

Syntax and Keywords

Operators

Command Effect
mov x, y xy
and x, y xx & y
or x, y xx | y
xor x, y xx ^ y
add x, y xx + y
sub x, y xxy
mul x EAXEAX * x
div x EAXEAX ÷ x
inc x xx + 1
dec x xx – 1

Instructions

Command Effect
cmp x, y Set the
jmp label When this line is reached, jump to the line labeled label
je label / jz label When ZF is 0, jump to label
jne label / jnz label When ZF is NOT 0, jump to label

Pseudo-instructions

Command Effect
syscall Invoke an operating system routine
db A pseudo-instruction that declares bytes that will be in memory when the program runs

section

A section is an assembler directive that tells the assembler what kind of code follows. Generally, you put code in a section called .text and your constant data in a section called .data.

Registers

32-Bit General Purpose

Address Name Description
EAX Accumulator Register calculations for operations and results data
EBX Base Register pointer to data in the DS segment
ECX Count Register counter for string and loop operations
EDX Data Register input/output pointer
ESI Source Index source pointer for string operations
EDI Destination Index destination pointer for string operations
ESP Stack Pointer stack pointer, should not be used
EBP Base Pointer pointer to data on the stack

16-Bit Segment

Address Name Description
CS Code Segment where instructions being executed are stored
DS, ES, FS, GS Data Segment data segment
SS Stack Segment where the stack for the current program is stored

32-Bit Other

Address Name Description
EFLAGS Code Segment status, control, and system flags
EIP Instruction Pointer offset for the next instruction to be executed

Flags

Carry Flag (CF)

The carry flag is set to 1 (true) when the second operand of an operation is smaller than the first. For example if you cmp 2 1, the result will be a CF of 1 (true), since 1 - 2 goes negative, meaning that the first operand is larger than the first.

Overflow Flag (OF)

The overflow flag will be set to 1 (true) if the operation overflows beyond the bounds of the integers and their storage. This could happen if you are dealing with numbers that go beyond the boundaries involved (e.g. adding two numbers that go above 256 with an 8-bit unsigned integer, or adding two 8-bit unsigned integers that go beyond 128).

Sign Flag (SF)

The sign flag will be set to 1 (true) after an arithmetic operation when the result is negative.

Zero Flag (ZF)

The zero flag is set after an arithmetic operation and will have a value of 1 (true) when the result is zero, and 0 (false) when the result is not zero.

Stack

The stack is used to invoke a function or as temporary storage by pushing parameters in last in first out to be utilized by the function.

This will push the number 3 onto the stack and then write it to the EAX register.

push 3
pop eax
ret

This will push three values to the stack in reverse order of what the function expects, because LIFO, and then invokes the function, which will use those values.

push [var] ; Push last parameter first
push 216   ; Push the second parameter
push eax   ; Push first parameter last

call _myFunc ; Call the function (assume C naming)

add esp, 12  ; Flush the three 4 byte values on the stack by 
      ; adding 12 to the stack pointer

Games

There are lots of games that have recently come out to make assembly a little more accessible. Here are the references I have found and heard about from others:

References

  1. https://www.tutorialspoint.com/assembly_programming/assembly_basic_syntax.htm
  2. https://www.youtube.com/watch?v=qhkEOyK1ek0
  3. https://www.youtube.com/watch?v=wLXIWKUWpSs
  4. https://doc.lagout.org/operating%20system%20/Windows/winasmtut.pdf
  5. https://www.cs.uaf.edu/2015/fall/cs301/lecture/09_16_stack.html
  6. https://www.cs.virginia.edu/~evans/cs216/guides/x86.html
  7. https://www.hellboundhackers.org/articles/read-article.php?article_id=729
  8. https://www.chibialiens.com/8086/8086CheatSheet.pdf
  9. https://www.chibialiens.com/8086/
Backlinks

Last modified: 202109270029

Assembly (Windows)

Assembly on Windows utilizes masm, Microsoft's proprietary assembler and linker.

Compilation, Linking, and Execution

Compiler

You will first need masm to compile your assembly into machine code. masm can be installed via the MASM32 SDK.

Your First Program

Create a file called hello_world.asm. Copy this into it's contents:

.386                  ; Tell assembler to use the 386 instruction set
.model flat, stdcall            ; Specify the flat memory model and use stdcall to pass parameters RtoL
option casemap :none          ; Force case sensitivity

include \masm32\include\windows.inc    ; Include Win32 API constants and defs
include \masm32\include\kernel32.inc   ; Include ExitProcess
include \masm32\include\masm32.inc     ; Include StdOut

includelib \masm32\lib\kernel32.lib   ; The libraries necessary for the above includes to function
includelib \masm32\lib\masm32.lib

.data                   ; The section for all initialized data
  HelloWorld db "Hello World!", 0    ; definebyte HelloWorld to equal Hello World! plus a NUL char

.code                    ; Starting point for program code
start:                   ; All code must live between this and end start
  invoke StdOut, addr HelloWorld    ; Run function StdOut with address of HelloWorld as the param 
  invoke ExitProcess, 0         ; Invoke ExitProcess with 0 (success) as the parameter

end start 

Assembling Your Code

Assembling your code will translate it from the human readable assembly language into a file object. The following command will run masm and create output hello_world.obj.

\masm32\bin\ml /c /Zd /coff hello_world.asm

Linking Your File

Linking your newly created output file will pull all the needed libraries into a single executable. The following command will run Link, the masmlinker, and finish the creation of your executable.

\masm32\bin\Link /SUBSYSTEM:CONSOLE hello_world.obj

Executing Your File

hello_world.exe
Hello, World!

Running hello_world.exe in the command line should result in the message being displayed.

masm-specific Syntax

invoke

invoke is a special function in masm to call functions without having to push parameters beforehand.

invoke SendMessage, [hWnd], WM_CLOSE, 0, 0

; equivalent to

push 0
push 0
push WM_CLOSE
push [hWnd]
call [SendMessage]

References

  1. https://doc.lagout.org/operating%20system%20/Windows/winasmtut.pdf
  2. https://masm32.com/
Backlinks

Last modified: 202107112140

Assembly (6502)

Assembly is an extremely low-level human-readable language that has a strong relation between the code and the corresponding machine code.

The Motorola 6502 is a microcontroller based on their 6800 series, but simplified, less expensive, and faster.

Memory Locations

$0000 - $00ff - Zero Page

This stores commonly used game variables as they can be accessed with only two digit addresses (see addressing modes).

$0200 - $05ff - Display

This stores values to be rendered on the display. Each row of the screen is represented by $20 values stored inline, rendering left to right. e.g. the first row of the screen is held in $0200 - $021f; the second row is held in $0220 - $023f.

Syntax

Literals

Type Syntax Notes
Binary %nnnnnnnn n is a binary digit. Trailing numbers can extend
Hexadecimal $xy xy are hex digits. Trailing numbers can extend
Decimal xy xy are decimal digits. Trailing numbers can extend

Flags

Flag Name Notes
C Carry Flag The carry flag is set if the last operation caused an overflow from bit 7 of the result or an underflow from bit 0. This condition is set during arithmetic, comparison and during logical shifts (or explicitly).
Z Zero Flag The zero flag is set if the result of the last operation as was zero.
I Interrupt Disable The interrupt disable flag is set if the program has executed a SEI instruction. While this flag is set the processor will not respond to interrupts from devices until it is cleared by a CLI instruction.
D Decimal Mode Flag While the decimal mode flag is set the processor will obey the rules of Binary Coded Decimal (BCD) arithmetic during addition and subtraction. The flag can be explicitly set using SED and cleared with CLD.
B Break Command The break command bit is set when a BRK instruction has been executed and an interrupt has been generated to process it.
V Overflow Flag The overflow flag is set during arithmetic operations if the result has yielded an invalid 2's complement result (e.g. adding to positive numbers and ending up with a negative result: 64 + 64 => -128). It is determined by looking at the carry between bits 6 and 7 and between bit 7 and the carry flag.
N Negative Flag The negative flag is set if the result of the last operation had bit 7 set to a one.

Addressing Modes

These will all use STA but can be used with any command that uses an address.

Type Syntax Effect
Absolute STA $c000 Look up the value at this full memory location
Zero page STA $c0 Look up the value at $00c0, c0 within the zero page
Absolute, X STA $c000,X Look up the value at $c000 + the value in register X (e.g. if X is $01, store value of A at memory location $c001)
Zero page, X STA $c0,X Look up the value at $00c0 + the value in register X (e.g. if X is $01, store value of A at memory location $c001)
Immediate #$c0 Use value $c0
Relative $c0 or label Go $c0 bytes forward/backward (to get to label position)
Implicit INX Do what instruction implies (no args)
Indirect STA $c000 Do instruction found at memory address $c000 and the following byte, with the first address being the least significant byte, and the following address the most significant byte. e.g. in this example, if $00c0 holds 01 and $00c1 holds 0f, it would dereference to $0f01.
Indexed Indirect STA ($c0,X) Store A at the address ($00c0 + X), with the resulting first address being the least significant byte, and the following address the most significant byte. e.g. in this example, if X was 01, we would look at the address $00c1. If $00c1 holds 01 and $00c2 holds 0f, it would dereference to $0f01.
Indirect Indexed STA ($c0),X Store A at the address found at $00c0 plus the value of X, with the resulting first address being the least significant byte, and the following address the most significant byte. e.g. in this example, lets say X was 01. We would look at the address $00c0. If $00c0 holds 01 and $00c1 holds 0f, it would dereference to $0f01 plus the value of X, resulting in $0f02.

Commands

A value refers to a number prefaced by a #, whereas an address/location refers to a hexadecimal address.

Command Argument(s) Effect
BRK Break out of the program
org $n $n: Number Set program origin to $n
LDA n n: value or memory address/location where value is stored Load n into register A
STA n n: memory address/location Store value in register A at n
TAX Transfer value in A to X
INX / DEX Increment/Decrement value in X by 1
ADC n n: value or memory address/location where value is stored Add n with carry to the A register

Flag Commands

These commands are used solely for the purpose of changing and setting flags.

Command Argument(s) Effect
CMP n / CPX n / CPY n n: value or memory address/location where value is stored Compare value at A/X/Y to n. If equal, set Z flag to 1; else, set Z flag to 0.
SEI / CLI Set/Clear Interrupt Disable

Branching

label: A label that must be within 256 bytes of invocation

Any label can be substituted for a direct memory address.

Command Name Effect
BEQ label Branch on EQual If Z flag is 1 (comparison was equal), go to label
BNE label Branch on Not Equal If Z flag is 0 (comparison was not equal), go to label
BCS label Branch on Carry Set If carry flag is 1 (set), go to label
BCC label Branch on Carry Clear If carry flag is 0 (not set), go to label
JMP label Unconditional Jump Jump directly to label
JSR label / RTS Jump to SubRoutine / ReTurn from Subroutine Jump directly to label and push current address - 1 to the stack. This will be retrieved via the return statement.

Stack

Command Name Effect
PHA PusH Accumulator Push the accumulator onto the top of the stack
PLA PulL (Pop) Accumulator Pop the accumulator off the top of the stack

Bitwise Operators

Command Parameters Effect
AND n n: Value or address Bitwise AND of value of n or value at address n against the accumulator register
LSR [n] n: Value or address (if omitted, default to accumulator) Bitwise shift right

References

Instructions and Flags Reference:

Backlinks

Last modified: 202110211443

Minicube64

Minicube64 is a fantasy console style emulator based on 6502, with the intention of helping people learn how games were made for older systems such as Atari 2600, NES or C64, but without many of the difficult hardware restrictions.

Annotated Introduction

The introduction page is what I'm annotating below. Hopefully these notes will give more insight into what the assembly is doing in the console.

Writing a New ROM

On the page "Writing a New ROM", there is a test program written in 6502 assembly. I figured a good way to learn what was going on was to annotate the whole thing and really grok it.

This is the contents of test.s:

include "64cube.inc"    ; Include the helper functinos for 64cube

ENUM $0                 ; Enumerate the following vars starting at $0000
  counter rBYTE 1        ; Set counter to type of byte with value of 1
ENDE                     ; End enumeration

  org $200              ; Specify the origin of the ROM program
  sei                    ; Set interrupt flag to 1
  ldx #$ff               ; Load 255 into X
  txs                   ; Transfer the contents of x to the stack
                        ;   pointer

  lda #$0               ; Load 0 into A
  sta VIDEO             ; Store A into VIDEO (location $100)

  _setw IRQ, VBLANK_IRQ  ; Store the address of IRQ at VBLANK_IRQ (in the
                        ;   include file)
  cli                   ; Clear interrupt flag

Infinite:                ; Set label for 'Infinite' at this address
  jmp Infinite          ; Jump to the 'Infinite' label, effectively
                        ;   creating an infinite loop

IRQ:                     ; Set label for 'IRQ' at this address
  inc counter            ; Increment the value at 'counter'
  rti                    ; Return to where the interrupt occurred

This is the relevant contents of 64cube.inc:

...

; NOTE NOTE
; normal 6502 has irq vectors at $fffe
; we have them at $010e
NMI_IRQ  = $10c
VBLANK_IRQ = $10e

...

MACRO   _setw value,dest  ; create a macro named _setw with two params:
                          ;   'value', and 'dest'
  lda #<value             ; load the high byte of value into register 'a'
  sta dest                 ; store the value in register 'a' at the address
                          ;   of destination
  lda #>value             ; load the low byte of value into register 'a'
  sta dest+1               ; store the value in register 'a' at the address
                          ;   of destination + 1
ENDM                      ; signify the end of the macro

Working With Pixels

This is the changed contents of the above test.s:

...
  txs

  ; This will set the video buffer page in a 4k page in memory
  lda #$f                    ; Load high byte of page into 'a'
                            ;   register
  sta VIDEO                 ; Store value in 'a' register at 'VIDEO'

  ; This will create a pixel of color #64 at pixel address $f820
  lda #$64                   ; Load decimal value 64 into 'a'
                            ;   register
  ;sta $f820                ; Store value in 'a' register at $f820
  sta $f000 + 32 + 32 * 64  ; Same as above but with MATH

  _setw IRQ, VBLANK_IRQ
...

Compiler Directives

Directive Args Effect
include n n: name of assembly file to be read Load in a remote assembly file and place the contents where include is invoked. Used for files containing assembly directives
incbin n n: name of binary file to be read Load in a remote binary file and place the contents where include is invoked. Not to be used for files containing assembly directives

Video Reference

Basic Drawing Example

This example shows how to set up a custom palette as well as drawing those colors to screen.

include "64cube.inc"      ; Include the helper functions

ENUM $0                    ; Enumerate values starting from $0000
  counter rBYTE 1          ; Set 'counter' as 1 byte
ENDE                      ; End enumeration

  org $200                ; Set program origin to $0200
  sei                      ; Set interrupt disable flag
  ldx #$ff                ; Load value $ff into X
  txs                      ; Transfer value of X into the stack
                          ;   pointer

  ; This will set the video buffer page in the $f000 page in memory
  lda #$f                  ; Load high byte of page into 'a'
                          ;   register
  sta VIDEO                ; Store value in A at 'VIDEO'

  ; This will set the colors buffer page in the $5000 page in memory
  lda #$5                  ; Load highbyte of page into 'a'
                          ;   register
  sta COLORS              ; Store value in A at 'COLORS'

  _setw IRQ, VBLANK_IRQ    ; Set value of VBLANK_IRQ to address of
                          ;   'IRQ' label
  jsr Draw                ; Jump to 'Draw' subroutine

  cli                      ; Clear interrupt disable flag

Infinite:                  ; Set 'Infinite' label
  jmp Infinite            ; Create infinite loop

IRQ:                      ; Set 'IRQ' label
  inc counter              ; Increment 'counter'
  rti                      ; Return from interrupt

Draw:                      ; Set 'Draw' label
  ; This will create pixels of colors from the palette below at address
  ;   $f820. The color is found by referencing the colors page at the
  ;   addresses listed below (#1, #2, #3).

  lda #0                  ; Create counter of 0 at A
  Loop:                    ; Create Loop label
    adc #1                ; Increment A
    tax                    ; Transfer value of A into X
    sta $f000 + 32 * 64 + 31,X   ; Store X into
                                ;   $f000 + 32 * 64 + 31 and X
    cmp #3                ; Compare x with 3
    bne Loop              ; If not equal go back to Loop
  rts                      ; Else return from subroutine

Palette:                          ; Set 'Palette' label
  ; This will set the palette of colors available in the COLORS page,
  ;   enumerating from $00 upward within that page.
  org $0500                        ; Set program origin to $0500
  hex 000000 ff0000 00ff00 0000ff  ; Set these colors in colors page

Video Address Locations

These are assuming the video page is being held in the 4k $f000 page.

Address Position
0xf000 Top Left
0xf03f Top Right
0xf820 Middle
0xffc0 Bottom Left
0xffff Bottom Right

References

  1. https://aeriform.gitbook.io/minicube64/
  2. https://itch.io/jam/minicubejam
  3. https://github.com/aeriform-io/minicube64/releases
  4. https://github.com/aeriform-io/minicube64/blob/main/memory_map.md

Last modified: 202110170408

Paper Computing

Paper computing is a way to learn about the most basic operation of Turing complete systems and programming in general. This is also a great way to get familiar with the basics of machine code and assembly.

Models

References

  1. https://en.wikipedia.org/wiki/Turing_completeness
  2. https://www.youtube.com/watch?v=RPQD7-AOjMI
  3. https://compudanzas.net/beans_computing.html
  4. https://www.youtube.com/watch?v=Z27KQiBnkJI
  5. https://www.youtube.com/watch?v=t-mOfXhgfQY
  6. https://wiki.xxiivv.com/site/papier.html
  7. https://www.instructables.com/CARDIAC-CARDboard-Illustrative-Aid-to-Computation-/
  8. https://www.cs.drexel.edu/~bls96/museum/cardiac.html
  9. https://archive.org/details/cardiac_201708/page/n9/mode/2up
  10. https://en.wikipedia.org/wiki/Little_man_computer
  11. http://elearning.algonquincollege.com/coursemat/dat2343/lectures.f03/12-LMC.htm
  12. http://www.pythondiary.com/blog/Oct.15,2014/building-cpu-simulator-python.html
Backlinks

Last modified: 202109270417

Assembly (Unix)

Assembly on Unix is largely the same between MacOS and Linux computers.

Compilation, Linking, and Execution

Compiler

You will first need a program to compile your assembly into machine code. Most common is the program nasm, which can be installed on OSX using homebrew with brew install nasm.

Your First Program

Create a file called hello_world.asm. Copy this into it's contents:

; ----------------------------------------------------------------------------------------
; Writes "Hello, World" to the console using only system calls. Runs on 64-bit macOS only.
; ----------------------------------------------------------------------------------------

        global    start                   ; nasm-specific way to define a location for the linker

        section   .text                   ; The .text section holds all the instructions for the 
                                          ; assembler to execute.
start:                                ; The label that is referenced in the above global call
        mov       rax, 0x02000004         ; system call for write (copy param Y into param X)
        mov       rdi, 1                  ; file handle 1 is stdout
        mov       rsi, message            ; address of string to output
        mov       rdx, 13                 ; number of bytes (message is 13 chars long)
        syscall                           ; invoke operating system to do the write
        mov       rax, 0x02000001         ; system call for exit
        xor       rdi, rdi                ; exit code 0
        syscall                           ; invoke operating system to exit

        section   .data                   ; The .data section contains constants
message:                              ; The label referenced above
        db        "Hello, World", 10      ; note the newline at the end

Assembling Your Code

Assembling your code will translate it from the human readable assembly language into a file object. The following bash command will run nasm using the Mach-O 64bit object -file notation format used by the 64-bit version of MacOS and create -output hello_world.o.

$ nasm -f macho64 hello_world.asm -o hello_world.o

Linking Your File

Linking your newly created output file will pull all the needed libraries into a single executable. The following bash command will run ld, the GNU linker, and finish the creation of your executable.

$ ld -macosx_version_min 10.7.0 hello_world.o -o hello_world

The -macosx_version_min flag is added to remove the warning that is present without it. I read that it still builds fine without it, but that has not been true in my experience.

Executing Your File

$ ./hello_world
Hello, World

Running ./hello_world in bash should result in the message being displayed.

References

  1. https://medium.com/@thisura1998/hello-world-assembly-program-on-macos-mojave-d5d65f0ce7c6
  2. https://cs.lmu.edu/~ray/notes/nasmtutorial/
  3. https://stackoverflow.com/questions/52830484/nasm-cant-link-object-file-with-ld-on-macos-mojave
  4. https://www.nasm.us/doc/
  5. https://www.youtube.com/watch?v=qhkEOyK1ek0
  6. https://www.youtube.com/watch?v=wLXIWKUWpSs
  7. https://github.com/camsaul/hello_world_x86_64_asm_os_x
  8. http://zathras.de/angelweb/blog-learn-nasm-on-os-x.htm
  9. http://caswenson.com/2009_09_26_assembly_language_programming_under_os_x_with_nasm
  10. https://lord.io/assembly-on-osx/
  11. https://orangejuiceliberationfront.com/intel-assembler-on-mac-os-x/
Backlinks

Last modified: 202107112052

Stack (Programming)

There's currently nothing here.

Backlinks

The Know-how Computer

The Know-how Computer is a simple pen-and-paper computer that was developed by Wolfgang Back and Ulrich Rohdein in the early 80's to help educate people on basic computing and assembly programming.

Setup

Materials

  • Piece of paper (ruled is best, but anything works)
  • Pen
  • Coins, matches, or some kind of enumerable item

Preparation

  • Fold your paper in half.
  • On the left half of the paper, number each line from 0 to 15. This is where your code will reside.
  • On the right half of the paper, create four boxes labeled R0 through R3. These are your registers and they will hold some number represented by your enumerables (e.g. 3 coins in R0 would mean that R0 has a value of 3).

You should now have something that looks something like this:

Line Code Register Value
0 R0
1 R1
2 R2
3 R3
4
5
6
7
...

Instructions

Before we get started, we need to learn some instructions. These are some of the most basic instructions in machine code and assembly and with these, you technically could compute anything as it's Turing complete (as long as you have a LOT of paper and a LOT of time).

Instruction Meaning
JMP n Jump to line n
INC Rn Increment the value in register n
DEC Rn Decrement the value in register n
ISZ Rn If the number in register n is zero, execute the next instruction. Else, skip the next instruction.
END Stop the execution of code and end the program.

Usage

First Program

For the most basic example, lets write a program that will decrement a register (DEC) until it reaches zero (ISZ), where we will end the program (END). We will assume that R0 has 3 in it, represented by 3 of whatever you are using. Lets start by writing it in plain English:

  • If R0 has a value of zero, end the program. Else, continue to the next instruction.
  • Decrease the value in R0 by 1.
  • Jump back to the beginning.

Now that we have this and have run through this in our head to ensure it works, we can put this into our instructions for our paper computer:

Line Instruction
0 ISZ R0
1 END
2 DEC R0
3 JMP 0

Start with a number of enumerables in R0 and go from line 0, using your pen as a pointer to which line you are currently on. Starting this program with any number will result in a constant decrementing until R0 reaches zero, where the program will end. Try it!

Addition

This is where things will get a little trickier to conceptualize. We will start with two values in different registers (R0 and R1) and add them together into a single register. This will take a little more breaking down before we can turn it into code.

Instead of being able to just move all of our enumerables from one register to another, we actually need to convert this into multiple instructions, since we don't have an instruction like ADD to make things easy. What is another way we can think of taking one thing from one register and putting it into another?

  • Remove one item from first register
  • Add one item to the second register
  • Repeat until first register is empty

So now that we've translated addition into language that our code can adapt to, lets finish by putting our whole program in plain English again, assuming that we are adding R0 and R1 together, with the result of our addition residing in R1:

  • If R0 is zero, end the program. Else, do nothing and continue.
  • Decrease the value in R0 by 1.
  • Increase the value in R1 by 1.
  • Jump back to the beginning.

These are now all much simpler to translate back into our instruction set:

Line Instruction
0 ISZ R0
1 END
2 DEC R0
3 INC R1
4 JMP 0

Now go ahead and try this with your paper computer, again putting any number of enumerables in R0 and R1 and using your pen as a pointer for the current line.

Challenges

With these challenges, you may need to extend the amount of lines and registers you have available. Don't be afraid to use as much as you need and streamline it later!

  1. Make a program that subtracts one number from another and completes with the difference in one register.
  2. Make a program that multiplies two numbers together and completes with the product in one register.
  3. Make a program that divides two numbers and completes with the quotient in one register and the remainder in another.

Solutions

This subtracts R0 from R1, so R1 must be larger than R0.

Line Instruction
0 ISZ R1
1 END
2 DEC R0
3 DEC R1
4 JMP 0

This multiplies the numbers in R0 and R1 together, placing the resulting product in R2.

Line Instruction
0 ISZ R1
1 END
2 DEC R1
3 ISZ R3
4 JMP 8
5 DEC R3
6 INC R0
7 JMP 3
8 ISZ R0
9 JMP 0
10 DEC R0
11 INC R2
12 INC R3
13 JMP 8

This divides the number in R0 by the number in R1, placing the quotient in R2 and the remainder in R3.

Line Instruction
0 ISZ R1
1 END
2 ISZ R0
3 END
4 ISZ R1
5 JMP 10
6 DEC R0
7 DEC R1
8 INC R3
9 JMP 2
10 INC R2
11 ISZ R3
12 JMP 2
13 DEC R3
14 INC R1
13 JMP 11

References

  1. https://en.wikipedia.org/wiki/WDR_paper_computer
  2. https://www.youtube.com/watch?v=Z27KQiBnkJI
  3. https://wiki.xxiivv.com/site/papier.html
Backlinks

Last modified: 202109262227

The Little Man Computer

The Little Man Computer is a simple pen-and-paper computer that was developed by created by Dr. Stuart Madnick in 1965 to help educate people on basic computing and assembly programming.

It is recommended you complete the Know-how Computer and its exercises before doing this one.

Setup

Materials

  • Piece of paper (grid paper is best, but anything works)
  • Pen
  • A calculator

Preparation

Note: If you don't want to make this yourself, download the PDF from Chris Staecker's Paper Computers #2: The Little Man Computer video, which you can find in the description.

The Little Man Computer consists of an inbox, an outbox, and a set of 100 mailboxes.

Turn your paper landscape and create a grid of 10x10, taking up about two thirds of the width of the page. Each of these boxes should be numbered 00 to 99, from top bottom, left to right. Split the last third of the page in half vertically, with the top half as the inbox, and the bottom half as the outbox.

Instructions

These instructions will take a little more work to learn, as they don't come with the ease of text to help with understanding.

Code Instruction Meaning
000 END Stop the execution of code and end the program.
1XY ADD Add the contents of mailbox XY to the current value of your calculator. This replaces the calculator's value with the result.
2XY SUB Subtract the contents of mailbox XY from the current value of your calculator. This replaces the calculator's value with the result.
3XY STA Store the value of your calculator in mailbox XY. This replaces the current value at mailbox XY.
5XY LDA Load the value of mailbox XY into the calculator. This replaces the current calculator value.
6XY BRA: Branch Set the next instruction to be the one contained in mailbox XY.
7XY BRZ: Branch If Zero (see note) If the calculator contains the value 0 (or 000 to be verbose), set the next instruction to be the one contained in mailbox XY. Else, continue.
8XY BRP: Branch If Positive (see note) If the calculator contains a positive value (between 0/000 and 999 inclusive), set the next instruction to be the one contained in mailbox XY. Else, continue.
901 INP Move the next value found in the inbox in the calculator. This removes the value from the inbox.
902 OUT Place the value found in the calculator in the outbox.

Inbox and Outbox

The inbox and outbox can hold multiple values in what is called a 'stack', where the last number that was placed in it will be the first one out. Think of it like a deck of cards, where the cards are pulled off of the top when removed, and when new cards are added, they will be added on top of the deck.

Calculator

The calculator holds a single value between 0/000 and 999 inclusive and can ADD and SUB. The calculator also has three indicators that are set by the last operation it has completed: negative, if the result is below 0; zero, if the result was exactly 0; and positive, for if the result is between 0 and 999 .

The calculator cannot handle numbers below 0/000, nor any numbers over 999. When executing subtraction, if the result ends up being below 0 (underflow), then this will cause the calculator to throw a negative flag, which would cause 7XY to succeed and 8XY to fail.

Mailboxes

Each mailbox can contain a number between 0/000 and 999. The mailboxes can contain both data upon which we are operating, as well as instructions we are looking to execute. Keep this in mind, as it's possible for our instructions to encroach on our data, and the Little Man will get confused and just stop working if he gets instructions he can't understand.

Process

The Little Man executes this process repeatedly until he runs out of stuff to do (taken from Wikipedia):

  1. Check the Program Counter (your pen, in this instance) for the mailbox number that contains a program instruction (i.e. zero at the start of the program).
  2. Fetch the instruction from the mailbox with that number. Each instruction contains two fields:
    • An opcode (indicating the operation to perform) and
    • the address field (indicating where to find the data to perform the operation on).
  3. Increment the Program Counter (pen) so that it contains the mailbox number of the next instruction.
  4. Decode the instruction. If the instruction utilises data stored in another mailbox, then use the address field to find the mailbox number for the data it will work on (e.g. 'get data from mailbox 42').
  5. Fetch the data (from the input, accumulator, or mailbox with the address determined in step 4).
  6. Execute the instruction based on the opcode given.
  7. Branch or store the result (in the output, accumulator, or mailbox with the address determined in step 4).
  8. Return to the Program Counter to repeat the cycle or halt.

Usage

Addition

Like in the Know-how Computer, we'll start with addition, but in this case it will be a little different. In this case, we just have an add command handy (1XY), so how hard can it be? :)

First, we will add two numbers to the inbox to eventually get added together. Our result will be in the output, of course. We know that to add two things together, one of our values will need to already be in the calculator, and the other value will need to be found in a mailbox. So before we get to adding, we will need to do that:

  1. Move the next value from the inbox into the calculator.
  2. Store that value in mailbox 50 (this is not a significant number, any mailbox above 30 or so will be fine).
  3. Move the next value from the inbox into the calculator.

So now we have the two numbers in place, ready to be added. Once we have this sum, we can place it into the outbox.

  1. Add the number in mailbox 50 to the calculator, replacing the calculator's old value with the sum.
  2. Put the value in the calculator into the outbox.

Now we can convert this into instructions that the Little Man can understand. Assuming we have our two numbers we want to add in the inbox:

Mailbox Instruction
00 901
01 350
02 901
03 150
04 902
05 000

Try this out with a few different numbers as inputs. Remember, the calculator can't handle numbers above 999.

Return The Largest Number

Again we'll start by putting two numbers into our inbox. The question is: how will we know which number to return? And how can we tell the Little Man to return one thing or another based on that condition? What if we reframed the question as: which of our branching tools could help us execute one sequence of code over another based on a condition?

We have two conditional branches: branch if (the value in the calculator is) zero, and branch if (the value in the calculator is) positive. If we know these are our only branching options, and that they are both dependent on mathematical operations in the calculator, this leaves us with only two instructions that could help us solve this problem: 1XY and 2XY; ADD and SUB.

If we try using ADD, you will see that adding two numbers in either order results in no discernable difference: 100 + 50 is the same as 50 + 100. So if we know this, then we are only left with the SUB instruction. Playing with SUB, we can see that the order definitely does matter. 100 - 50 (50) does not equal the same as 50 - 100 (-50).

So knowing that we will need to use SUB leaves us with which branch we want to use: 7XY or 8XY; branch if zero, and branch if positive. If we look at the last example of 100 and 50, we can see that one of the differences is positive and the other negative. This would lead to us using the branch if positive instruction after we perform our subtraction method.

Now that we know our tools, lets put this in plain English:

  1. Load one number from the inbox into the calculator.
  2. Store the number in our calculator into mailbox 50.
  3. Load the next number from the inbox into the calculator.
  4. Store the number in our calculator into mailbox 51.
  5. Subtract the number in mailbox 50 from the current value of the calculator (this number should be the same as is in mailbox 51).
  6. If the result is positive, return the number in mailbox 51.
  7. Else, return the number in mailbox 50.

Now we can translate this into code the Little Man can understand:

Mailbox Instruction
00 901
01 350
02 901
03 351
04 250
05 809
06 550
07 902
08 000
09 551
10 902
11 000

Challenges

  1. Create a program that takes four numbers from the inbox and outputs them in reverse order.
  2. Create a program that adds all numbers in the inbox, ending with a zero, and outputs the final sum. For example, an inbox of [13, 426, 301, 95, 0] would result in 835.
  3. Create a program that squares a number and outputs the product. The inbox number must be 31 or below.
  4. Create a program that divides the first number in the inbox by the second. The output will be the quotient followed by the remainder.
  5. Create a program that takes in numbers followed by operators and calculates the result of the sequence. These operators are 401 for add, 402 for subtract, and 400 for equals. For example, an inbox of [20, 402, 15, 401, 95, 400] would output 100.
  6. Update your last program to handle multiplication and floor division (return only the quotient with no remainder).

Solutions

Assuming we have four numbers in our inbox.

Mailbox Instruction/Data
00 901
01 350
02 901
03 351
04 901
05 352
06 901
07 902
08 552
09 902
10 551
11 902
12 550
13 902
14 000

Assuming the last number in the inbox is a zero.

Mailbox Instruction/Data Data Note
00 901
01 705
02 108
03 308
04 600
05 508
06 902
07 000
08 000 Total
Mailbox Instruction/Data Data Note
00 901
01 315
02 317
03 517
04 712
05 516
06 150
07 316
08 517
09 218
10 317
11 603
12 516
13 902
14 000
15 000 Number from inbox
16 000 Total
17 000 Times number has been added
18 001

The first number in the inbox will be divided by the second.

Mailbox Instruction/Data Data Note
00 901
01 317
02 901
03 318
04 517
05 218
06 812
07 517
08 902
09 519
10 902
11 000
12 317
13 519
14 120
15 319
16 604
17 000 Number
18 000 Divisor
19 000 Quotient
20 001
Mailbox Instruction/Data Instruction/Data Note
00 901
01 350
02 901
03 252
04 808
05 550 "Equals"
06 902
07 000
08 715
09 901 "Subtract"
10 351
11 550
12 251
13 350
14 602
15 901 "Add"
16 150
17 350
18 602
...
50 000 Total
51 000 Temp
52 401 To determine operator

References

  1. https://en.wikipedia.org/wiki/Little_man_computer
  2. https://www.youtube.com/watch?v=t-mOfXhgfQY&lc=UgwXIu1pFzxIC7pJyLd4AaABAg.9Slg5diLl1j9Slgcj6WvW6
Backlinks

Last modified: 202109271334

Canvas

The Canvas API provides a means for drawing graphics via JavaScript and the HTML <canvas> element.

Initialization

To start using the canvas, put the canvas element in your webpage HTML, along with a width or height in pixels. Fallback content goes in between the opening and closing tag.

<canvas id="canvas-name" width="150" height="150"></canvas>

The canvas is initially blank and then needs to be accessed, with the new context assigned to a variable. This variable will become the way to draw on the canvas.

var canvas = document.getElementById('canvas-name');
var ctx = canvas.getContext('2d');

Drawing

Canvas only supports rectangles and paths.

Rectangles

ctx.fillRect(x, y, width, height)   // Draws a filled rectangle.
ctx.strokeRect(x, y, width, height) // Draws a rectangular outline.
ctx.clearRect(x, y, width, height)  // Clears the specified rectangular area, making it fully transparent. 

Paths

From MDN:

A path is a list of points, connected by segments of lines that can be of different shapes, curved or not, of different width and of different color. A path, or even a subpath, can be closed. To make shapes using paths, we take some extra steps:

  1. First, you create the path with beginPath()
  2. Then you use drawing commands to draw into the path
  3. Once the path has been created, you can stroke or fill the path to render it with closePath()
ctx.beginPath() // Creates a new path. Once created, future drawing commands are directed into the path and used to build the path up.
ctx.closePath() // Adds a straight line to the path, going to the start of the current sub-path.
ctx.stroke()    // Draws the shape by stroking its outline.
ctx.fill()      // Draws a solid shape by filling the path's content area. 

Path Methods

moveTo(x,y) moves the pen without recording it as a path to be drawn or filled.

lineTo(x,y) should be used to draw straight lines.

arc(x, y, radius, startAngle, anticlockwise) will draw an arc centered at x, y.

arcTo() is often used to make rounded corners https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arcTo

quadraticCurveTo(cp1x, cp1y, x, y) and bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) are also good for [rounded shapes](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#paths.

References

Last modified: 202108151812

Web Fonts (HTML)

To import a font from Google Fonts, you can copy the font(s) URL from the Google Fonts library and then paste it in your HTML. For this challenge, we'll import the Lobster font. To do this, copy the following code snippet and paste it into the top of your code editor (before the opening style element):

<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">

Now you can use the Lobster font in your CSS by using Lobster as the FAMILY_NAME as in the following example:

font-family: FAMILY_NAME, GENERIC_NAME;

The GENERIC_NAME is optional, and is a fallback font in case the other specified font is not available.

References:

  1. https://www.freecodecamp.org/learn/responsive-web-design/basic-css/import-a-google-font

Last modified: 202107020536

Anchor Tags (HTML)

In-page Navigation

Using an #id as your href and either setting the name attribute of an anchor tag or the id of an element, you can navigate immediately within a document via a normal anchor link.

<a href="#bob">Click here to go to bob!</a>

<!-- a bunch of other stuff -->

<a name="bob"></a>
<!-- or -->
<div id="bob">
  <img src="pic/of/bob" />
</div>

Download

Using the download attribute will instruct the browser to download the file enclosed in the value of the download attr. The value is optional.

<a href="file.pdf" download>Download Here</a>
<a href="file.pdf" download="new-filename.pdf">Download Here</a>

So far I have not seen the attribute force a download of a file, but I have seen it change the download name of the file re: things like PDFs.

References

  1. https://stackoverflow.com/questions/23825871/how-to-force-a-download-file-prompt-instead-of-displaying-it-in-browser-with-htm
  2. https://www.w3schools.com/tags/att_a_download.asp

Last modified: 202108191542

Semantic HTML

HTML without any styling or functionality should be readable and the user should easily be able to discern context about the content.

Headings

Headings should be used for semantics only, not for font sizing (HTML for structure, CSS for styling).

Heading information can be used by user agents to construct a table of contents for a document automatically.

Use only one <h1> per page or view. It should concisely describe the overall purpose of the content. Using more than one <h1> will not result in an error, but is not considered a best practice. Using only one <h1> is beneficial for screenreader users, and SEO. Avoid skipping heading levels: always start from <h1>, followed by <h2> and so on.

References

  1. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements
Backlinks

Last modified: 202107020535

HTML Tables

The basics of HTML5 tables and semantic HTML tables.

Summary of All Elements

<table summary="Extended summary for accessibility and screen readers">
  <!-- caption or title -->
  <caption>Caption</caption>
  <thead>
    <!-- row -->
    <tr> 
      <!-- col header -->
      <th abbr="Shortened heading for accessibility/screen readers" scope="col">Header 1</th>
      <th abbr="Shortened heading for accessibility/screen readers" scope="col">Header 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <!-- row header -->
      <th abbr="Shortened heading for accessibility/screen readers" scope="row">Row Header</th>
      <!-- table data -->
      <td>Some data</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td>Footer data 1</td>
      <td>Footer data 2</td>
    </tr>
  </tfoot>
</table>

More complex tables with empty cells/row headers have added accessibility needs, like scope="col/row" depending on what the header organizing.

Merging Cells

The colspan attribute is used to span a single cell across multiple columns within a table, while the rowspan attribute is used to span a single cell across multiple rows. Each attribute accepts an integer value that indicates the number of cells to span across, with 1 being the default value.

<tr rowspan="2">
   <td colspan="3">...</td>
</tr>

This can't be done using CSS. It must be done using inline styles.

Borders

The border-collapse property determines a table’s border model. There are three values for the border-collapse property: collapse, separate, and inherit. By default, the border-collapse property value is separate, meaning that all of the different borders will stack up next to one another, as described above. The collapse value, on the other hand, condenses the borders into one, choosing the table cell as the primary border.

The border-spacing property may accept two length values: the first value for horizontal spacing and the second value for vertical spacing.

References

  1. https://learn.shayhowe.com/html-css/organizing-data-with-tables/
  2. https://www.456bereastreet.com/archive/200410/bring_on_the_tables/

Last modified: 202107020535

Emmet

There's currently nothing here.

Backlinks

Sublime Text

Sublime Text is an application made for software development.

Command Line Shortcut

To create a symlink in bash that will allow you to open any folder in Sublime Text:

echo 'export PATH="/Applications/Sublime Text.app/Contents/SharedSupport/bin:$PATH"' >> ~/.bash_profile
// or
echo 'export PATH="/Applications/Sublime Text.app/Contents/SharedSupport/bin:$PATH"' >> ~/.zprofile

Now you can just type subl . in a given folder, a la code . in Visual Studio Code

Key Bindings

Multiple Commands

Sublime Text 4 provided the ability to chain multiple commands and args together, while Sublime Text 2 and 3 required the use of the Chain Of Command plugin. Both use the same syntax:

{
    // Link Opener
    // This example uses https://github.com/NoxArt/SublimeText2-LinkOpener
    {
        "keys": ["super+shift+u"],
        "command": "chain",
        "args": {
            "commands": [
                ["expand_selection", {"to": "smart"}],
                ["link_opener_open_url"]
            ],
        }
    }
}

Troubleshooting Errors

Autocompletion/Snippets

  1. Open the console (View > Show Console or ctrl + ` on OSX).
  2. In the console, enter in sublime.log_commands(True).
  3. Do what you need to recreate the issue. Immediately after triggering the unwanted behavior, document what you think is causing it that is in the console. In my case it was command: insert_snippet {"contents": ":$0;"}.
  4. Depending on which syntax you are in, or which plugin is listed/suspected, use the command palette to View Package File and type in the syntax/plugin. This will show files that are hidden, as well, which makes diagnosing issues with default plugins/syntaxes much easier. In my case this was in the keymap file.
  5. Once you find a possible file, open it. Save As in the Packages directory under a new folder called the name of the plugin or syntax. e.g. for the Sass plugin/syntax, I created a folder in Packages called Sass and saved a copy of the Default.sublime-keymap file there, which included my additions. You can find more on overriding packages here.
  6. In my case, I copied the old rule over and changed the {"contents": ":$0;"} object to {"contents": ":$0"}, which allowed the colon to be typed without adding any additional characters.

Syntax Highlighting

Packages in Sublime Text are interdependent on each other and many of the default packages are inferior to third-party (e.g. Babel over Javascript). When nested syntaxes are not cooperating, in this example Pug's Javascript syntax, you can Disable Package > Javascript and install Babel and this will cause Pug to correctly highlight conditionals and the succeeding code.

References

  1. https://milofultz.com/2021/03/06/sublime-keymap
  2. https://stackoverflow.com/questions/59635627/how-to-override-sublime-text-3-packages-css3-completion-syntax
  3. https://www.sublimetext.com/docs/command_line.html#mac
Backlinks

Last modified: 202108230316

Pug

Pug is a templating engine for HTML that allows you to write a simpler more condense webpage, as well as integrating Javascript to dynamically generate pages.

Getting Started

Install it using NPM: npm i -g pug-cli. You can compile a Pug file directly, or by watching the file and it's dependencies for changes.

# compile the single file
pug filename.pug -o ./outputfolder
# watch the file and its dependencies for changes and compile on change
pug -w filename.pug -o ./outputfolder

Iteration/Testing

You can do quick testing of code at https://pughtml.com/.

Syntax

Writing HTML in Pug is very similar to Emmet shorthand/selectors in CSS.

element#id.class(attr="value" foo="bar") innerText

doctype html
html(lang="en")
  body
    header#header.header.header__wrapper
      .header__logo
        span
          img.header__logo-img(src="..." alt="Logo")
          |  Some <b>text</b>!
      h1 Company Name

//- outputs

//- <!DOCTYPE html>  
//-  <html lang="en">
//-   <body>
//-     <header id="header" class="header header__wrapper">
//-       <div class="header__logo">
//-         <span><img src="..." alt="Logo" /> Some &lt;b&gt;text&lt;/b&gt;!</span>
//-       </div>
//-       <h1>Company Name</h1>
//-     </header>
//-   </body>
//- </html>

Comments

// This comment will appear in the HTML

//- This is a silent comment

//-
  Nesting inside a comment creates
  a comment block

Javascript

Any line that starts with a hyphen or anything that follows an equals sign in an attribute list can be valid Javascript.

- var num = 6;
- var name = "John Smith";

h1(data-name= name.replace(/\s/, '.').toLowerCase())= `This guy is probably ${num} feet tall!`

//- outputs
//- <h1 data-name="john.smith">This guy is probably 6 feet tall!</h1>

Inserting Unescaped HTML/Javascript

To insert unescaped HTML/Javascript that is located within a string, preface the string with an exclamation and enclose it with curly braces.

- var num = 6;
- var name = "John Smith";

- const john = `This guy is <i>probably</i> ${num} feet tall!`;
h1(data-name= name.replace(/\s/, '.').toLowerCase()) !{john}
p !{'this <b>is it</b>'}

//- outputs
//- <h1 data-name="john.smith">This guy is <i>probably</i> 6 feet tall!</h1>
//- <p>this <b>is it</b></p>

On a Text Node

- const test = "Yeah!";

p
  span thing!
  = test

//- Outputs:
//- <p><span>thing!</span>Yeah!</p>

Inline

h1: span.header Yeah!

//- Outputs
//- <h1><span class="header">Yeah!</span></h1>

Multiline

p.
  This text can be broken 
  up on multiple lines

p
  img(src="stuff")
  | This works, too.

//- outputs
//- <p>This text can be broken
//-     up on multiple lines</p>
//- <p><img src="stuff" />This works, too.</p>

script.
  console.log('or here');
  // Works for script tags, as well.

Self-Closing Tags

hr 
//- outputs <hr/>

foo/
//- outputs <foo/>

Imports / Include

Pug allows import of HTML directly as well as Pug files.

include filename.pug
include another.html

Variables

Variables in Pug are defined as they are in Javascript and should be preceded by a hyphen. Multiline variable definitions are done by starting a line with a hyphen, leaving no whitespace, and continuing indented on the next line. As long as the indentation remains, you will be in "Javascript land".

- var location = 'russia';
-
  var obj = {
    thing: "one",
    otherThing: "two",
  }

p= location
span(class= obj.thing) OK

//- outputs 

//- <p>russia</p>
//- <span class="one">OK</span>

Conditionals

- var location = 'russia';
- var cold = true;

if location === 'los-angeles'
  p Party!
else if location === 'mexico'
  p MORE Party!
else if cold
  p cold party
else
  p no party

span= cold ? "Brr!" : "*panting*"

//- outputs 
//- <p>cold party</p>
//- <span>Brr!</span>

Iteration

Arrays

- var items = ['candy', 'cake', 'ice cream'];

each item in items
  p.item(id= item.replace(' ', '-'))= item.toUpperCase()

//- outputs
//- <p id="candy" class="item">CANDY</p>
//- <p id="cake" class="item">CAKE</p>
//- <p id="ice-cream" class="item">ICE CREAM</p>

Objects

- 
  var people = {
    'John': 'Johnson',
    'Ashley': 'Ashtown',
  };

each last, first in people
  p= first + ' ' + last

//- outputs
//- <p>John Johnson</p>
//- <p>Ashley Ashtown</p>

Mixins

Mixins allow one piece of code to be reused over and over with different variables, returning a modified version of the template within the declaration.

The mixin needs to be declared and defined. It's usually easiest to do this in a separate file and include them in. Lets call this _mixins.pug:

//- Here the mixins are declared

mixin makeStrong(text)
  strong= text

mixin makeList(list)
  ul.generated-list
    each item in list
      li= item

Then the file that will use them needs to include that file:

include _mixins.pug

- const faveFoods = ['pizza', 'pie', 'spaghetti'];

h1 This is my list!
.contents
  p
    +makeStrong('I love these foods!')
  +makeList(faveFoods)

Compiling this will return this HTML:

<h1>This is my list!</h1>
<div class="contents">
  <p><strong>I love these foods!</strong></p>
  <ul class="generated-list">
    <li>pizza</li>
    <li>pie</li>
    <li>spaghetti</li>
  </ul>
</div>

Blocks

You can pass in a block to a mixin, where a block is some pug that is "within" the mixin invocation. The block is called by name within the mixin itself. In _mixins.pug:

mixin wrapper
  section.wrapper
    block

In the main file:

include _mixins.pug

+wrapper
  h1 the REAL content
  p.yeah this is some stuff

Outputs:

<section class="wrapper">
  <h1>the REAL content</h1>
  <p class="yeah">this is some stuff</p>
</section>

Sublime Text Syntax

Packages in Sublime Text are interdependent on each other and many of the default packages are inferior to third-party (e.g. Babel over Javascript). When Pug's Javascript syntax is not cooperating or popping to allow Pug's syntax to take over again, you can Disable Package > Javascript and install Babel and this will cause Pug to correctly highlight conditionals and the succeeding code.

If this does not work, you can switch over to Pug (Python) and that will do ok.

References

  1. https://www.sitepoint.com/a-beginners-guide-to-pug/
  2. https://pughtml.com/
  3. https://devhints.io/pug
  4. https://pugjs.org/language/conditionals.html
  5. https://pugjs.org/language/includes.html
  6. https://cssdeck.com/labs/learning-the-jade-templating-engine-syntax
  7. https://stackoverflow.com/questions/27107451/how-to-insert-raw-html-in-pug-file-not-include-external-html-file
  8. https://pugjs.org/language/mixins.html
  9. https://github.com/davidrios/pug-tmbundle/issues/22
Backlinks

Last modified: 202110172303

HTML Forms

The basics of HTML forms, semantic HTML forms, and validation.

Form Element

The action attribute that defines the action to be done upon submission as an address or href. The method is the HTTP method to use in completing the action.

Input Types

Input

  • Pre-HTML5 input types:
    • button
    • checkbox
    • file
    • hidden
    • image
    • password
    • radio
    • reset
    • submit
    • text
  • HTML5 input types:
    • color
    • date
    • datetime
    • email
    • month
    • number
    • range
    • search
    • tel
    • time
    • url
    • week

These values were added to provide clearer semantic meaning for inputs as well as to provide better controls for users. Should a browser not understand one of these HTML5 type attribute values, it will automatically fall back to the text attribute value.

Label

The label element provides a label for an input element, with its for="" attribute referencing the id attribute of the element it is to label.

<input type="text" id="thing">
<label for="thing">Thing!</label>

Select

The size attribute chooses how many choices are visible at a time. The boolean attribute multiple, when added to the <select> element for a standard drop-down list, allows a user to choose more than one option from the list at a time.

<label for="things">Things!</label>
<select id="things" name="things" multiple>
  <option value="thing1">Thing 1</option>
  <option value="thing2" selected>Thing 2</option>
</select>

Textarea

A textarea has rows and columns attributes to determine the size, but can be done more efficiently with CSS styling.

Button

Always include type="button" for compatability across browsers.

<button type="button">Click Here</button>

Radio Buttons and Checkboxes

A radio button and checkbox input element can be checked by default by adding the checked boolean attribute to the input field. This requires them being within a form element; otherwise they will not select correctly in all browsers.

Fieldsets and Legends

Fieldsets group form controls and labels into organized sections. Much like a <section> or other structural element, the <fieldset> is a block-level element that wraps related elements, specifically within a <form> element, for better organization. The <legend> element wraps text describing the form controls that fall within the fieldset. The markup should include the <legend> element directly after the opening <fieldset> tag.

<form action="">
  <fieldset>
    <legend>Thing Description:</legend>
    <label for="things">Things!</label>
    <select id="things" name="things" multiple>
      <option value="thing1">Thing 1</option>
      <option value="thing2" selected>Thing 2</option>
    </select>
  </fieldset>
</form>

Field Validation

Input

Use the correct input type (text, email, password, etc.)

The pattern attribute is used to specify a regular expression and the field value must match this pattern. This attribute can be used with input types like text, password, email, url, tel and search. Validation occurs upon submission.

<!-- Should match if five numbers from 1 to 4 appear in a row -->
<input type="text" pattern="[1-4]{5}"> 

A required attribute indicates that a value must be specified for the input element.

<input type="text" required>

maxlength is an integer value that specifies the maximum number of characters allowed for a particular input field.

<input type="text" maxlength="20">

min & max attributes specify the lower and upper limit respectively for an input element.

<input type="number" min="1" max="5">

References

  1. https://www.w3schools.com/html/html_form_elements.asp
  2. https://stackoverflow.com/questions/3606657/radio-buttons-checked-attribute-not-working

Last modified: 202107020534

Fetch API

Fetch API is a part of vanilla Javascript that does HTTP requests.

Usage

The syntax for fetch is fetch('URL'). fetch() ALWAYS returns promises. These promises will be fulfilled when the data is finished loading, and can be accessed with .then(function (response) { ... }). Within .then, you can resolve this promise with .json(), .text(), or .blob(), which all return their own promise. Errors are handled through a .catch(function (response) { ... }).

fetch('http://web.site')
  .then(function (response) {
    // response is a Promise, so it will be resolved within this function
    return response.json();
    // response.json is *also* a Promise
  }).then(function (json) {
    // do thing with JSON response
  }).catch(function (error) {
    console.log(error);
  });

With async/await

If you encapsulate the fetch call within a function, you can declare that function as an async function and make the calls inside the function await. Because it's an async function, it will also return a promise, which can be handled by .then and .catch.

var getJSON = async function () {
  var response = await fetch('http://web.site');
  var json = await response.json();
  // do thing with JSON response
};

getJSON().catch(function (error) {
  console.log(error);
});

References

  1. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
  2. https://www.youtube.com/watch?v=tc8DU14qX6I
  3. https://www.youtube.com/watch?v=RfMkdvN-23o
Backlinks

Last modified: 202107020539

Jest

Jest is a Javascript test framework built by Facebook for for use with Node/Javascript applications.

Mocking

You can mock functions like fetch or axios by using the jest.fn(() => {}) syntax.

const someBlackBox = jest.fn(number => 42 + number);
forEach([0, 1], someBlackBox);

// The mock function is called twice
expect(someBlackBox.mock.calls.length).toBe(2);

// The first argument of the first call to the function was 0
expect(someBlackBox.mock.calls[0][0]).toBe(0);

// The first argument of the second call to the function was 1
expect(someBlackBox.mock.calls[1][0]).toBe(1);

// The return value of the first call to the function was 42
expect(someBlackBox.mock.results[0].value).toBe(42);

You can force certain return values, as well.

const someOtherBlackBox = jest.fn();
console.log(someOtherBlackBox()); // undefined

someOtherBlackBox.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);
console.log(
  someOtherBlackBox(), // 10
  someOtherBlackBox(), // 'x'
  someOtherBlackBox(), // true
  someOtherBlackBox()  // true
);

expect(someOtherBlackBox.mock.calls.length).toBe(4);
// etc. etc.

References

  1. https://jestjs.io/
  2. https://jestjs.io/docs/mock-functions
  3. https://www.leighhalliday.com/mock-fetch-jest
Backlinks

Last modified: 202110181402

Test-Driven Development

In programming, test-driven development is when tests are developed first before the code is written.

In test-driven development the mantra has always been, red, green, refactor. Write a failing test and run it (red), make the test pass (green), then refactor it (that is look at the code and see if you can make it any better).[1]

  • You can’t write any production code until you have first written a failing unit test.
  • You can’t write more of a unit test than is sufficient to fail, and not compiling is failing.
  • You can’t write more production code than is sufficient to pass the currently failing unit test.

These last two points are very important to fully understand, and may feel insane at first. If you were making an add function and you created your first test that add(2, 2) === 4, then your first step would be to create the add function and then have it return 4.

const add = (first, second) => {
  return 4;
}

// tests

if (add(2, 2) !== 4) {
  console.error('FAILURE: 2 + 2 !== 4');
}

It is important to note that of course this is incorrect as an adding function, but

You can’t write more production code than is sufficient to pass the currently failing unit test

Once you have this, you would want to create more tests. And sometimes that will result in more stupid-feeling tests:

const add = (first, second) => {
  if (first === 2) {
     return 4; 
  } else {
    return 6;
  }
}

// tests

if (add(2, 2) !== 4) {
  console.error('FAILURE: 2 + 2 !== 4');
}
if (add(5, 1) !== 6) {
  console.error('FAILURE: 5 + 1 !== 6');
}

But as we write more and more, we will triangulate into what is accurate and necessary with nothing more. You will get to a point where refactoring the code will make you write less code than you currently have, and that is the end goal, but you don't want to get there until it is necessary.

Remember, that you should at this point be trying really hard to find ways to BREAK your code. What are the edge cases? What is something user X or Y or Z would do, and how would my code be affected?

const add = (first, second) => {
  // Instead of continuing to add more if blocks, we refactored
  if (first === undefined) {
    return null;
  } else if (second === undefined) {
    return first;
  }
  return first + second;
}

// tests

if (add(2, 2) !== 4) {
  console.error('FAILURE: 2 + 2 !== 4');
}
if (add(5, 1) !== 6) {
  console.error('FAILURE: 5 + 1 !== 6');
}
if (add(2, 0) !== 2) {
  console.error('FAILURE: 2 + 0 !== 2');
}
if (add(2) !== 2) {
  console.error('FAILURE: 2 !== 2');
}
if (add() !== null) {
  console.error('FAILURE: Run add without args');
}

Best Practices

Write the test that forces you to write the code you already know you want to write.

Avoid the central behaviors as long as possible. Don't go for the gold right away.

Decouple the production code from the test code by ensuring your tests are not 1:1 for the class methods or functions. Create and refactor as you go in production, but allow the tests to remain.

Dependency Injection

Use dependency injection to make testing simpler. If you have an API call, inject axios or fetch as an argument so when it comes to testing, your testing framework won't be brittle in its imports. e.g. In this example, we make a call to an external API to get the tax rate of a given country using the Javascript native fetch API, with tests using Jest.

getTaxRate.js

// works, but brittle
const getTaxRates = (country) => {
  return fetch(`external.api/example/${country}`)
    .then(response => response.json())
    .then(taxRateInfo => taxRateInfo.rate)
}

// best, robust
const getTaxRates = (fetch, country) => {
  return fetch(`external.api/example/${country}`)
    .then(response => response.json())
    .then(taxRateInfo => taxRateInfo.rate)
}

Using the brittle implementation, our tests are coupled with the implementation of the code we are testing, which will lead to problems if these global imports or functions like fetch ever change.

getTaxRate.test.js

// assuming all imports

// This will properly mock the return value of the external API
const mockFetchImplementation = () => {
  return Promise.resolve({
    json: () => Promise.resolve({
      rate: 10
    });
  });
};

// brittle implementation
// Fetch gets used invisibly, non-explicitly, and is more difficult to see what is happening.
// Fetch as a global is also being overwritten, which may not be desired for future tests.

global.fetch = jest.fn(mockFetchImplementation);

describe('getTaxRates', () => {
  it('gets a tax rate for a given country (brittle)', () => {
    return getTaxRates('DE')
      .then(taxRate => {
        expect(taxRate).toBe(10);
        expect(fetch).toHaveBeenCalledTimes(1);
      });
  });
});

// robust implementation
// Fetch obviously gets used, easy to see high-level view
// Uses a local mock and doesn't overwrite global fetch.

const fakeFetch = jest.fn(mockFetchImplementation);

describe('getTaxRates', () => {
  it('gets a tax rate for a given country (brittle)', () => {
    return getTaxRates(fakeFetch, 'DE')
      .then(taxRate => {
        expect(taxRate).toBe(10);
        expect(fetch).toHaveBeenCalledTimes(1);
      });
  });
});

Why Use TDD

  • Your code will ALWAYS be working just a second ago when you last tested.
  • It is double-entry bookkeeping for development.
  • A test suite that you don't trust is worthless. A test suite that does not allow you to make a decision when it passes is useless. There can be NO HOLES.

References

  1. https://github.com/gregmalcolm/python_koans
  2. Clean Code
  3. https://qualitycoding.org/3-laws-tdd/
  4. Examples of TDD in action
  5. https://www.youtube.com/watch?v=XsFQEUP1MxI&list=PL0zVEGEvSaeF_zoW9o66wa_UCNE3a7BEr&index=2
  6. https://wallabyjs.com/?referrer=funfunfunction
Backlinks

Last modified: 202110181410

K6

K6 is an open-source load testing program for API's via Javascript.

Basics

$ brew install k6

Create a new file, script.js, to hold your basic script:

import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('https://test.k6.io');
  sleep(1);
};

Now run your new test in your terminal with k6 run script.js.

Design

You can design your tests with startup code that runs only once and the defaut function, which will be run over and over for the duration of the test by each virtual user.

// init code

export default function() {
  // vu code
}

Metrics

Field Description
http_req_blocked Time spent blocked (waiting for a free TCP connection slot) before initiating the request.
http_req_connecting Time spent establishing TCP connection to the remote host.
http_req_duration http_req_sending + http_req_waiting + http_req_receiving
http_req_failed The rate of failed requests according to setResponseCallback.
http_req_receiving Time spent receiving response data from the remote host.
http_req_sending Time spent sending data to the remote host.
http_req_tls_handshaking Time spent handshaking TLS session with remote host
http_req_waiting Time spent waiting for response from remote host (a.k.a. "time to first byte", or "TTFB").
http_reqs Total requests
iteration_duration The time it took to complete one full iteration of the default/main function.
iterations The aggregate number of times the VUs in the test have executed the JS script (the default function).
vus_max Max possible number of virtual users

Options

Options can be included in your script as an export called options:

export let options = {
  vus: 10,
  duration: '30s',
};

If these options are to be used in a CLI, they should be prefaced with two hyphens and followed directly by their argument.

Flag Args Effect
duration n: string formatted as {number}s, indicating number of seconds Duration of test
vus n: integer Number of virtual users to be utilized in the test

References

Last modified: 202108060551

React (Testing)

Testing Software

Suites

The suite of choice is definitely Jest, as Jest was built almost 100% specifically for the purpose of testing React by Facebook who developed it).

Next best would be Mocha/Chai, as these play nicer with Mongoose servers, as Mongoose doesn't play nice with the concurrency of Jest.

Helper Libraries

I've found React Testing Library to handle most of my use cases, as it gives you a way to handle front-end testing like a user would, with mouse clicks, input entry, and searching for elements in the DOM.

Enzyme is another alternative, but I have yet to try it out in a project.

Unit/Component Tests

Rendering With No Props

To test components, an easy test to put in place before even getting started, in the spirit of Test-Driven Development, is a "default" rendering. This is a rendering of the component passing in no props whatsoever, which will give you a good idea of what will happen in the non-happy paths.

This example is largely based off of this article.

Component.jsx

import React from 'react';

export default function Component({ content, list }) {
  return (
    <div>
      <h1>Test</h1>
      <p>{content}</p>
      <ul>
        {list.map(item => <li>{item}</li>)}
      </ul>
    </div>
  )
}

First we start off with our component, which without adding defaults would throw explicitly, as you can't map over list when list is undefined. There would also be an empty <p> element as an undefined variable will render empty.

So when we write our test, we should check for that unwanted text and ensure it won't show up in our output, as well as bypass that list error by using defaults. So when we write our test, lets write it as if those things are in place.

Component.test.jsx

import React from 'react';
import '@testing-library/jest-dom';
import {render, screen} from '@testing-library/react';
import Component from '../Component.jsx';

describe('Testing Component', () => {
  it('should render without any props passed in', () => {
    // Render component with nothing passed in.
    // This will throw if any outright JS errors crop up.
    render(<Component />);
    // Check for elements rendering empty from no content
    // (Must use `queryBy` or else it will throw)
    const undefinedContent = screen.queryByTestId('content');
    expect(undefinedContent).toBeNull();
    // Check that the list is empty
    const emptyList = screen.getByRole('list');
    expect(emptyList).toBeInTheDocument();
    expect(emptyList.children.length).toBe(0);
  });
});

With these tests in place, the tests will error out until the defaults are put in place. So with these additions, we can make our component a little more robust right off of the bat:

Component.jsx

import React from 'react';

export default function Component({ content, list }) {
  return (
    <div>
      <h1>Test</h1>
      {content && <p data-testid="content">{content}</p>}
      <ul>
        {list.map((item, index) => <li key={index}>{item}</li>)}
      </ul>
    </div>
  )
}

Component.defaultProps = {
  list: [],
};

References

  1. https://rangle.io/blog/component-test-coverage/
  2. https://www.chaijs.com/
  3. https://mochajs.org/
  4. https://jestjs.io/
  5. https://testing-library.com/docs/react-testing-library/intro/
  6. https://enzymejs.github.io/enzyme/
  7. https://stackoverflow.com/questions/52783144/how-do-you-test-for-the-non-existence-of-an-element-using-jest-and-react-testing

Last modified: 202110181350

Text Compression (Server)

Text compression minifies and zips files on build or on client side rendering of your web page. Using this on your deployed webpage can save significant time in page downloads and lead to better user retention.

Implementation

To accomplish client-side rendering, you will need to implement the compression on the building of your pages (in this case, using Webpack) as well as on your server (Express). This example is for a React project using Webpack and Express.

Webpack

First, install compression-webpack-plugin and add it to your webpack.config.js file:

module.exports = {
  ...
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.(js|css)$/i,
    }),
  ],
  ...
};

This will use GZIP to compress all JS and CSS files in your project.

Express

Similar to Express's app.use(express.static(...)), this will allow Express to serve the GZIP files to the user. You need to install express-static-gzip and then add this to your server JS file:

var express = require("express");
var expressStaticGzip = require("express-static-gzip");
var app = express();

app.use("/", expressStaticGzip("/my/rootFolder/"));

On Your Server

On your server, add/merge your new code, npm i all the new dependencies, restart any PM2 instances and NGINX, and away you go!

References

  1. https://developers.google.com/speed/pagespeed/insights/
  2. https://stackoverflow.com/questions/57504666/enable-text-compression-using-react-webpack-and-apache
  3. https://stackoverflow.com/questions/50442039/compression-webpack-plugin

Last modified: 202107010334

Visual Studio Code

Visual Studio Code/Codium is an open-source application developed by Microsoft for software and code development.

Extensions Missing

If an extension is found on VS Code but not on VS Codium, it can still be installed by sideloading it as a VSIX. "You'll have to sideload that extension since the marketplace that VS Codium uses is OpenVSX which hosts only open source extensions"[1].

You can download it on the website and in the "Extensions" pane of VS Codium, click the dots up top and choose "Install VSIX".

References:

  1. https://www.reddit.com/r/vscode/comments/lt8y62/live_share_missing_from_extension_marketplace/
  2. Live Share
Backlinks

Last modified: 202107020502

Arrays (Javascript)

Arrays in Javascript have many specific methods for modification and analysis. Some are cunfusiong or hard to recall.

Methods

reduce

reduce will iterate through the items in the array and operate the callback function on each one, passing the previous value's result post-callback. Because of this, reduce can be used to build most array methods from scratch.

reduce takes up to two params: the callback function, and the initial value.

Callback

The callback function can take up to four params:

  • previousValue oraccumulator
  • currentValue
  • currentIndex
  • array

The result of this callback function will go into the previousValue/accumulator and then the currentValue will become the next item in the array. At the end of the iteration, the previousValue is what is returned from the reduce function.

Initial Value

This value is going to be passed in to the callback function for the first item in the array, where no previousValue/accumulator would otherwise exist.

If no initial value is provided, the previousValue/accumulator will be set to the first item in the array, and the currentValue will be set to the second item in the array.

Examples

Check Condition on All Items

By setting the callback to require that both the accumulator be true and that the value is evenly divisible by 2, this will check that all values pass the condition. Without the accumulator check, it will only return whether the last item in the list is even.

const evenArray = [2,4,6,8];
const mixedArray = [2,3,4,5,6];
evenArray.reduce((acc, val) => acc && val % 2 === 0, true); // returns true
mixedArray.reduce((acc, val) => acc && val % 2 === 0, true); // returns false
Sum All Items

This works by initially setting the sum to the first value in the array, and then adding that to each successive value.

const numbers = [1,2,3,4,5];
numbers.reduce((sum, val) => sum + val); // returns 15
Filter Out Odd Numbers
const numbers = [1,2,3,4,5];
numbers.reduce((resultArray, val) => {
  if (val % 2 === 0) {
    resultArray.push(val);
  }
  return resultArray;
}, []); // returns [2,4];
Conditional Map: Return All Values Over 2 Divided By 2
const numbers = [1,2,3,4,5];
numbers.reduce((resultArray, val) => {
  if (val > 2) {
    const newNum = val / 2;
    resultArray.push(newNum);
  }
  return resultArray;
}, []); // returns [1.5, 2, 2.5];

Destructive Methods

These methods affect the array the method is called upon.

sort

The sort function can work with or without a sorting function that sorts in place. Without, it will simply convert every value into a string and compare via Unicode point value. With, it follows this formula: .sort(compareFunction).

From MDN:

If compareFunction(a, b) returns a value > than 0, sort b before a. If compareFunction(a, b) returns a value ≤ 0, leave a and b in the same order.

An example compare function:

const array = [3,2,4,1];

const compareFunction = (a, b) => {
  if (a < b) {
    // leave a before b
    return -1;
  } else if (a > b) {
    // place b before a
    return 1;
  } else { // a === b
    // leave a before b
    return 0;
  }
};

array.sort(compareFunction); // array now equals [1,2,3,4]

splice

Splice works for both removal and insertion of array elements. Splice operates in place and will return whatever elements were spliced from the array.

splice(start, deleteCount, [item, ...])

let array = [1,2,3,4];
array.splice(1); // returns [2,3,4]; array now equals [1]

array = [1,2,3,4];
array.splice(1,1); // returns [2]; array now equals [1,3,4]

array = [1,2,3,4];
array.splice(1,1,17); // returns [2]; array now equals [1,17,3,4]

Last modified: 202109101553

Testing (Javascript)

Javascript provides many options to test your code via timing, assertions, and frameworks.

Time

Simplest Timer

console.time('process');
// do stuff
console.timeEnd('process'); // log time passed since console.time

Basic Timer Polyfill

var Timer = function(name) {
  var start = new Date();
  return {
    stop: function() {
      var end  = new Date();
      var time = end.getTime() - start.getTime();
      console.log('Timer:', name, 'finished in', time, 'ms');
    }
  }
};

var t = new Timer('Description');
// do stuff
t.stop();

Last modified: 202107020540

Operators (Javascript)

Logical Operators

In Javascript, all of these operators on truthy and falsy values, meaning that all values will be converted to boolean before comparison.

Used with Non-Boolean Types

When using non-boolean values, the return value will not be a boolean, but one of the values compared.

AND (&&)

If all are truthy, it will return the last compared value. However, if any of the values are falsy, if will return the first falsy value.

const a = 1 && 2 && 3; // returns 3
const b = 4 && 0 && 'yes' && false // returns 0

AND Assignment (&&=)

If x is truthy, define x with what follows. This is fairly new, so only use this if you know if will be safe to use in production.

let x = 4;
let y = false;
x &&= 10; // x === 10
y &&= true; // y === false

OR (||)

OR will return the first truthy value found. If all are falsy, will return the last value.

const a = 1 || 2 || 3; // returns 1
const b = null || 0 || false; // returns false

OR Assignment (||=)

If x is falsy, define x with what follows. This is fairly new, so only use this if you know if will be safe to use in production.

let x = 4;
let y = false;
x ||= 10; // x === 4
y ||= true; // y === true

NOT (!)

Using a double NOT will convert a regular value into a boolean.

const a = !!'hello'; // returns true
const b = !!0; // returns false
const c = !!undefined; // returns false

Nullish Operator (??)

Will return the right hand side operand if the left side is null or undefined.

const a = 0 ?? 2; // returns 0
const b = null ?? 2; // returns 2

Nullish Assignment (??=)

If x is nullish (null or undefined), define x with what follows. This is fairly new, so only use this if you know if will be safe to use in production.

let x = 4;
let y = undefined;
x ??= 10; // x === 4
y ??= true; // y === true

References

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators

Last modified: 202106291353

Classes (Javascript)

Classes in Javascript generally are created with two different sections:

  1. The prototypes or methods will be how all the instances of the class should be similar (things like addYear for a person class). This is commonly done in the prototype object.
  2. The constructor will define how the instances are different (the name property of a person class). This is commonly done through the invocation of the constructor, like function (name) { this.name = name }.

Class Types

Decorators

A decorator is a function that accepts an object and adds more properties or functionality to it. It's common to use adjectives as the names of these decorators. Decorators allow for more DRY code and help keep all elements together that should be, allowing little ambiguity in execution.

// this decorator makes obj more 'carlike'
var carlike = function (obj, loc) {
  obj.loc = loc;
  obj.move = function () {
    obj.loc++;
  };
};

var newObj = {};
var newCar = carlike(newObj, 0);

Functional Classes

A functional class is a construct that is capable of making a fleet of objects that conform to the same interface. They are commonly capitalized in name. The functions that produce these functional classes are called constructors. The object that is returned is called an instance of that class.

The difference between a decorator and a functional class is that a decorator accepts their target object as input, whereas the class builds and returns the object it's augmenting.

var Car = function (loc) {
  var obj = {loc: loc};
  obj.move = function () {
    obj.loc++;
  }
  return obj;
}

var newCar = Car(0);

Functional Classes with Shared Methods

Using shared methods allows you to save space in memory, as only one instance of a method needs to exist, as opposed to one for every single instance.

var Car = function (loc) {
  var obj = {loc: loc};
  // using UnderscoreJS (see polyfill)
  return _.extend(obj, carMethods);
}

var carMethods = {
  move: function () {
    this.loc++;
  }
}

var newCar = Car(0);

_.extend polyfill:

var extend = function (destination, source) {
  for (var key in source) {
    destination[key] = source[key];
  }
  return destination;
}

Prototypal Classes

Using Object.create(), we can create an object that inherits all properties of the enclosed object into its prototype. This will mean that on a failed lookup, it will search within this object for a reference, inheriting the old objects as they were at the time of inheritance.

var Car = function (loc) {
  var obj = Object.create(Car.prototype);
  obj.loc = loc;
  return obj;
}

Car.prototype.move = function () {
  this.loc++;
};

var newCar = Car(0);

Pseudoclassical Classes

The pseudoclassical class is a Javascript syntactic sugar that allows a more conventional style of object oriented programming to be implemented.

By running a function with the new keyword before it, the interpreter runs the program in a special "construction" mode. Since you will always want to be creating an object and returning it when you are finished, the new keyword adds these two lines at the beginning and end, respectively, to your function. The object created will be automatically bound to this and will use the prototype property found inside that function.

The two different parts of a pseudoclassical class are doing two distinct roles:

  1. the constructor is defining what is different about each instance. In this example, what loc is.
  2. the methods are defining what is similar about each instance. In this example, what move does.
var Car = function (loc) {
  // var this = Object.create(Car.prototype);
  this.loc = loc;
  // copy all prototypes to `this`
  // return this;
};

Car.prototype.move = function () {
  this.loc++;
};

var newCar = new Car(0);

ES6 Classes (class)

The ES6 implementation is extremely similar to the pseudoclassical implementation, but uses more syntactic sugar to make it more readable and more similar to other object-oriented languages.

class Car {
  constructor(loc) {
    // var this = Object.create(Car.prototype);
    this.loc = loc;
    // copy all prototypes to `this`
    // return this;
  }

  move() {
    this.loc++;
  }
}

var newCar = new Car(0);

Polymorphism

Polymorphism is the design of objects to be able to share behaviors and override certain shared behaviors to work more specifically on the new object. There is a super class and a sub class. The sub class inherits the properties and methods from the super class. In the following examples, the super is Shape and the sub is Square or Triangle.

Functional Classes

var Shape = function (name, sides, sideLength) {
  var obj = {
    name: name,
    sides: sides,
    sideLength: sideLength
  };
  var calcPerimeter = function () {
    return obj.sides * obj.sideLength;
  };
  return obj;
};

var Square = function (name, sideLength) {
  var obj = shape(name, 4, sideLength);
  var calcArea = function () {
    return Math.pow(obj.sideLength, 2);
  };
  return obj;
}

var newSquare = Square('square', 5);

Functional with Shared Methods

Using _.extend to update the object.

var Shape = function (name, sides, sideLength) {
  var obj = {
    name: name,
    sides: sides,
    sideLength: sideLength
  };
  // using UnderscoreJS (see polyfill)
  return _.extend(obj, shapeMethods);
};

var shapeMethods = {
  calcPerimeter: function () {
    return this.sides * this.sideLength;
  }
};

var Square = function (name, sideLength) {
  var obj = Shape(name, 4, sideLength);
  return _.extend(obj, squareMethods);
}

var squareMethods = {
  calcArea: function () {
    return Math.pow(this.sideLength, 2);
  }
};

var newSquare = Square('square', 5);

Prototypal Classes

Using Object.create().

var Shape = function (name, sides, sideLength) {
  var obj = Object.create(Shape.prototype);
  obj.name = name;
  obj.sides = sides;
  obj.sideLength = sideLength;
  return obj;
};

Shape.prototype.calcPerimeter = function () {
  return this.sides * this.sideLength;
};

var Square = function (name, sideLength) {
  var obj = Object.create(Square.prototype);
  obj.name = name;
  obj.sides = 4;
  obj.sideLength = sideLength;
  return obj;
}

Square.prototype = Object.create(Shape.prototype);
Square.prototype.constructor = Square; // otherwise is `Shape`
Square.prototype.calcArea = function () {
  return Math.pow(this.sideLength, 2);
};

var newSquare = Square('square', 5);

Pseudoclassical Classes

Using the new keyword.

var Shape = function (name, sides, sideLength) {
  // this = Object.create(Shape.prototype);
  this.name = name;
  this.sides = sides;
  this.sideLength = sideLength;
  // return this;
};

Shape.prototype.calcPerimeter = function () {
  return this.sides * this.sideLength;
};

var Square = function (name, sideLength) {
  this.name = name;
  this.sides = 4;
  this.sideLength = sideLength;
};

Square.prototype = new Shape();
Square.prototype.constructor = Square; // otherwise is `Shape`
Square.prototype.calcArea = function () {
  return Math.pow(this.sideLength, 2);
};

var newSquare = new Square('square', 5);

ES6 Classes

To create a class that inherits all the properties of another class, use extends after defining the class name.

class Shape {
  constructor (name, sides, sideLength) {
    this.name = name;
    this.sides = sides;
    this.sideLength = sideLength;
  }

  calcPerimeter () {
    return this.sides * this.sideLength;
  }
};

class Square extends Shape {
  constructor (name, sideLength) {
    super(name, 4, sideLength);
  }

  calcArea () {
    return Math.pow(this.sideLength, 2);
  }
}

var newSquare = new Square('square', 5);

Property Lookup/Prototype Chains

If you are looking for a given property of an object, the interpreter will first look at the object itself, and if it fails on that lookup, will look at any other objects that are associated via prototype chain.

To have an ongoing prototype chain, where one object will always default on a failed lookup to searching within another object, you can use var newObj = Object.create(oldObj). newObj will now default to looking up any failed lookups in oldObj. The values will be calculated during the lookup time, as the values are not stored or copied into the new object. The new object has a link to the old object and will perform on a lookup on the old object in its current state.

References

  1. http://underscorejs.org/#extend
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
  4. https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Test_your_skills:_Object-oriented_JavaScript
  5. https://stackoverflow.com/questions/44391149/es6-classes-ability-to-perform-polymorphism
  6. https://radialglo.github.io/blog/2014/11/24/understanding-pseudoclassical-inheritance-in-javascript/

Last modified: 202110021709

Promises and Async/Await (Javascript)

Promises and async/await are a way to handle asynchronous actions in Javascript.

Promises

const getDataFromAPI = () => {
  // do stuff
  return fetch('url')
};

function main () {
  let apiData;
  getDataFromAPI()
    .then(data => apiData = data)
    .catch(error => console.error(error));

  if (apiData) {
    // do stuff
  }
}

Async/Await

const getDataFromAPI = () => {
  // do stuff
  return fetch('url')
    .then(data => apiData = data)
    .catch(error => console.error(error));
};

async function main () {
  let apiData;
  try {
    apiData = await getDataFromAPI();
  } catch (error) {
    console.error(error);
  }

  if (apiData) {
    // do stuff
  }
}

References

Last modified: 202109281427

How To Load Local JSON Files

Put the local JSON file in a Javascript file and prepend the JSON with const variableName = and just treat it like an object literal. Put the file you created before your main app file in the HTML and you will be able to access it.

Last modified: 202107020540

Socket.IO

Socket.IO is a node/Javascript package that enables real-time, bidirectional and event-based communication between the client and the server.

Getting Started

Create a new node project and install Socket.IO using npm or yarn (the package name is socket.io), and install express for your server.

We're going to make the simplest possible implementation, that will allow a user to send a message via console to all other users who are on the same site.

To run and test this, install the above dependencies and create these three files. Once they are created and populated, you can run nodemon server.js and open multiple tabs/windows at http://locathost:3000 on your machine. With the console open, you should see messages coming in from the other tabs when sending messages on any of them.

index.html

<html>
  <body>
    <form id="chat-form">
      <input id="msg" type="text" required/>
      <button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="index.js"></script>
  </body>
</html>

index.js

const form = document.getElementById('chat-form');

// Connect to the server socket
const socket = io();

// When a `message` event is received
socket.on('message', (id, message) => {
  console.log(`${id}: ${message}`);
});

form.addEventListener('submit', (e) => {
  e.preventDefault();

  // Emit a `message` event to the server
  socket.emit('message', socket.id, e.target.children.msg.value);
});

server.js

const express = require('express');
const http = require('http');
const path = require('path');
const socketio = require('socket.io');

// Set up Express
const app = express();
const port = 3000;
app.use(express.static(path.join(__dirname, '/')));

// Set up Socket.IO
const server = http.createServer(app);
const io = socketio(server);

// When user connects, run the callback
io.on('connection', (socket) => {
  // When a `message` event is received
  socket.on('message', (id, message) => {
    console.log(`${id}: ${message}`);

    // Emit a `message` event to everyone
    io.emit('message', id, message);
  });
});

server.listen(port, () => {
  console.log('Listening at http://localhost:3000');
});

Syntax

Emitters

Each of these takes an eventName followed by an arbitrary number of args to send along with the emission.

Client

socket.emit(eventName, [...args]) will emit a message to the server.

Server

Assuming these emits are wrapped in an io.on('connection', ... event listener. This will give the server access to the current user.

Command Effect
socket.emit(eventName, [...args]) Emits a message to the current user.
socket.broadcast.emit(eventName, [...args]) Emits to every user BUT the current user.
io.emit(eventName, [...args]) Emits to ALL users.

Listeners

Callback takes in an eventName and [...args]

Command Args Effect
socket.on(eventName, callback) Runs the listener on event.
socket.once(eventName, callback) Runs the listener only once on event.
socket.off(eventName, callback) Same callback as was instantiated in socket.on Removes a listener by function.
socket.onAny(callback) Fires on any event.
socket.offAny([callback]) Same callback as was instantiated in onAny Removes a listener by function. If no callback, removes all listeners.
socket.removeAllListeners([eventName]) Removes all listeners for a given event name. If no eventName given, removes ALL listeners.

Rooms

A user joins a room using socket.join('some room'). A user leaves a room using socket.leave('some room').

Using .to('some room') prior to .emit(...) will emit the events to only those who are in that room.

References

Last modified: 202110221451

Higher Order Functions

A higher-order function either takes in a function as an argument, or returns a function.

Callback Functions

When taking a function as a parameter, this is called a callback function. This is used in Javascript built-ins like setTimeout, filter, map, and forEach.

var arr = [1,2,3,4];
var add2 = function (num) {
  return num + 2;
};
var newArr = arr.map(add2); // result: [3,4,5,6]

Closures

Functions that return other functions can create closures, which means that the variables within which the function is defined will remain accessable by that function; the variables are enclosed within that function's own scope.

In the example below, a function called counter keeps track of how many times it is called. Even though the function runs and fully completes, the reference to this execution context remains with the function that is returned at the conclusion of that invocation. We cannot directly access count from outside of the scope of counter, but with the returned function, we can add to it and see what count's value' is at that point.

var counter = function () {
  var count = 0;
  console.log(count);
  var add1 = function () {
    count++;
    console.log(count);
  };
  return add1;
};

// newCounter will now reference the `add1` function within the closure of that invocation of counter
var newCounter = counter(); // 0
// This calls `add1` within that same closure, incrementing `count` by 1
newCounter(); // 1

References

  1. https://en.wikipedia.org/wiki/Higher-order_function
Backlinks

Last modified: 202106291359

Apply, Call and Bind in Javascript

Apply, bind, and call are higher order functions that help with this.They allow you to invoke a function, which would normally be called from and on the same object, and change which object to which it will be applied.

Apply and Call

// functionName.apply(newThis, [arguments, moreArguments]);
// functionName.call(newThis, arguments, moreArguments);

const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max); // expected output: 7

const min = Math.min.apply(null, numbers);
console.log(min); // expected output: 2

While the syntax of apply and call are almost identical, the fundamental difference is that apply accepts an array of arguments, and call accepts a comma-separated argument list.

Bind

The bind() method returns a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

var num = 2;
var x = { num: 6 };

var addTwo = function () {
  return this.num + 2;
};

var addTwoToX = addTwo.bind(x);

addTwo();    // returns 4 since this.num = 2
addTwoToX(); // returns 8 since this.num = 6

References:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Backlinks

Last modified: 202106291328

Switch Case (Javascript)

Switch cases in Javascript act very similar to if/else statements with one very important caveat, being that they will trip the condition that matches and all that follow it unless a specific break is made. Default is a special case that will only trip if no other conditions are met or if break is not invoked.

const number = 1;

switch (number) {
  case -1:
    console.log('Definitely negative 1');
    break;
  case 1:
    console.log('True');
    break;
  case 0:
    console.log('False');
    // Will fall through to default as no explicit `break` was made
  default:
    console.log('Definitely not -1');
}

// Logs 'True'
// number = 2: 'Definitely not -1'
// number = 0: 'False', 'Definitely not -1'

References

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch

Last modified: 202106291341

MutationObserver (Javascript)

The MutationObserver interface in Javascript provides the ability to watch for changes being made to the DOM tree.

This is an example that will watch an element (targetElement) on a webpage that has dynamic elements generated via React, and update another element whenever it sees the targetElement change.

// Select the node that will be observed for mutations
const videoPlayer = document.querySelector('.video-main');

// Options for the observer (which mutations to observe)
const config = {
  attributes: false,
  childList: true,
  subtree: true,
  characterData: true
};

// Callback function to execute when mutations are observed
const copyVideo = (mutationsList, observer) => {
  document.querySelector('.iframe__inner-container').innerHTML = videoPlayer.innerHTML;
  if (!videoPlayer.innerHTML.includes('video-placeholder')) {
    observer.disconnect();
    blPlayer.querySelector('iframe').src = '';
  }
};

// Create an observer instance linked to the callback function
const wrapperObserver = new MutationObserver(copyVideo);

// Start observing the target node for configured mutations
wrapperObserver.observe(videoPlayer, config);

References

  1. https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
  2. https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/

Last modified: 202110090009

DOM Manipulation (Javascript)

How to manipulate the HTML DOM using Javascript.

Elements

  • X = document.createTextNode('text')
  • X = document.createElement('li')

Alteration

<!-- beforebegin -->
<p>
  <!-- afterbegin -->
  foo
  <!-- beforeend -->
</p>
<!-- afterend -->
  • X.textContent = 'text'
  • X.innerText = 'text'
  • X.childNodes[n].nodeValue = '...' will allow you to change the inner text of an element, even when it includes another element (e.g. changing some more text in <span><em>yeah</em>some more text</span>)

Insertion

  • X.appendChild(Y) will append element Y as the last child of element X
  • X.prepend(Y) will prepend element Y as the first child of element X
  • X.parentNode.insertBefore(Y, X); will insert element Y directly before element X
  • X.parentNode.insertBefore(Y, X.nextSibling); will insert element Y directly after element X

Duplication

  • X.cloneNode(true) will return a copy of the selected element.

Search

  • X.querySelector(Y) will find the first element based on CSS element search Y within the tree of elements found at X.
  • X.querySelector(Y) will find all elements based on CSS element search Y within the tree of elements found at X.
  • X.closest(Y) will find an element based on CSS element search Y from element X up through all of the parents to the top of the DOM

DOMParser

The DOMParser allows you to parse HTML in as a string, returning an HTMLDocument object. This allows you to interact with the DOM elements and alter them much more simply and easily than using regex or find/replace in a text-editor.

The DOMParser operates very similarly to jQuery's ability to parse HTML in as a string within $('<input>'). The difference is that DOMParser returns an HTMLDocument instead of a jQuery object.

Importing Plain Text

const parser = new DOMParser();
const htmlDoc = parser.parseFromString(input, 'text/html');

Exporting Plain Text

You can return each of the top level elements (head, body) as plain text using innerHTML.

return htmlDoc.body.innerHTML;

References

  1. https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
  2. https://api.jquery.com/jQuery/
  3. https://www.udemy.com/course/modern-javascript-from-the-beginning/learn/lecture/8757274
  4. https://gomakethings.com/how-to-copy-or-clone-an-element-with-vanilla-js/
  5. https://stackoverflow.com/questions/4106809/how-can-i-change-an-elements-text-without-changing-its-child-elements
  6. https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML

Last modified: 202109110002

Object Destructuring (Javascript)

Object destructuring in Javascript allows you to create constants from items within an object.

How

const initialObject = {
  first: 123,
  second: ['yeah', 'no'],
  third: {
    thing: 1,
    another: 2
  }
};

console.log(initialObject.first) // 123
console.log(initialObject.second[0]) // 'yeah

Basic

const { first, second, third } = initialObject;

console.log(first) // 123
console.log(second[0]) // 'yeah'

Custom Names

const { first: tom, second: cruise, third: hello } = initialObject;

console.log(tom) // 123
console.log(cruise[0]) // 'yeah'

References

Last modified: 202108102210

Lexical Scoping (Javascript)

Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.

With Javascript, a new scope is created only through function definitions. Every time a new function scope is created, it will contain the scope of the parent functions, along with its own. This does not go both ways, however: the outer scope does not have access to those in the inner scope.

var content = "I'm outside";
var outermost = " and I'm still here."

var middle = function () {
  var content = "I'm in the middle";
  var inner = function () {
    var content = "I'm inside"; 
    console.log(content + outermost);
  };
  inner();
  console.log(content + outermost);
};

middle();
// from `inner()`: "I'm inside and I'm still here."
// from `middle()`: "I'm in the middle and I'm still here."
console.log(content + outermost);
// "I'm outside and I'm still here."

this

this, within a function, is bound to the object within which the function is being called. Look to the left of the calltime dot to find the binding of this. The Javascript interpreter binds this to a likely-focal object, which means it isn't always what you think it is. Assume its binding will run into trouble, so you may need to at times manually set this to the desired object.

  • If you have defined your function in the global scope, then this is implicitly bound to the global context, which in a browser is window. You can call this function funcName also by calling window.funcName
  • If you have defined your function as part of an object, like var obj = { funcName: function (a) { ... } }, then this is bound to obj.
var obj = {
  greeting: function () {
    console.log(this.message);
  },
  message: "Hello world"
}

obj.greeting(); // => "Hello world"
// Equivalent to `window.obj.greeting()`
// `this` is bound to `obj`
// The `greeting` invocation defines `obj` as `this`

var g = obj.greeting;
g(); // => undefined
// Equivalent to `window.g()`
// `this` is bound to the *global object* (i.e., `window`)
// The `greeting` invocation defines `window` as `this`

References:

  1. https://stackoverflow.com/questions/1047454/what-is-lexical-scope
  2. http://howtonode.org/what-is-this
  3. https://medium.com/better-programming/how-javascript-works-1706b9b66c4d

Last modified: 202110091808

Variables (Javascript)

All variables in Javascript are undefined by default after declaration.

Difference Between Var, Let, and Const

Use const over let and let over var unless:

  • The value may change
  • The var needs to be initialized
  • It is used in an iterator or a loop

Block scoped means within a block or indentation level (starting with { and ending with }) or outside of a function. This means that one can use let outside of a function and declare a new variable with let again within a function.

const

const is block scoped. Short for "constant", meaning that it is a variable that once defined, cannot be redefined, changed through reassignment, redeclared, or updated. This also means one can cannot initialize a variable through const without a value. const can only be accessed within the scope they were created.

const greeting = "Hello there!";
// This can never be changed, as it is a constant.
greeting = "Hi."; // This throws an error

Reference types created with const can have their attributes updated, but cannot be updated itself.

 const greeting = {
    "brothers" = 3;
}

// Not accepted, since `greeting` is has already been declared and assigned a value
const greeting = {
    "sisters" = 2;
}

const brothers = 1; // Accepted
const brothers; // Unaccepted

let

let is also block scoped; let variables can be updated, but not redeclared.

let greeting = "Hello there!";
greeting = "Hi.";
// This throws an error and won't work
let greeting = "Hey hey hey";

var

var variables are function scoped and not a constant. Even when defined within a function, they can affect the global scope. These variables can also be redeclared and updated at any point.

As of ES2015, const and let are fully supported in modern browsers, so var is not advised.

var greeting = "Hello there!";
var greeting = "Hey bayBEE!";
//These are all acceptable

Define Multiple Variables At Once

One can use commas to const many different variables at once.

const yes = 'yes',
      no = 'no',
      hi = 'hi';

Global Declaration

Global variable declarations are made by using no keyword before the definition:

greeting = "Hi.";

Assignment as an Expression (a la Walrus Operator)

You can define a variable while running a condition on an if or a while loop. This can help remove extra lines of code or going through variables over and over. Since the innermost parentheses get resolved first, it will function normally after assignment.

let i = 0;
while (i !== 3) {
  console.log(i);
  i++;
}

// Logs (0, 1, 2)

// Written using assignment as an expression

let i = -1;
while ((i = i + 1) < 3) { // === (i = i + 1) < 3 === i < 3
  console.log(i);
}

// Logs (0, 1, 2)

Hoisting

The JS code interpretation performed in two passes. During the first pass, the interpreter processes variable and function declarations. The second pass is the actual code execution step. The interpreter processes function expressions and undeclared variables.[7]

Hoisting Variables

The term "hoisting" is meant to represent a literal hoisting of variable and function declarations to the top of a Javascript file, where they will be declared before the file is interpreted (while this is not technically what happens, it's certainly more memorable).

Consider the following example:

var a = 1;
console.log(a + ' ' + d);
var d = 3;

In this example, because interpreters normally run from top to bottom, executing each line as they go, one would expect an error thrown at the console.log because it would not be aware of any variable named d. Because of hoisting, however, d is declared by the interpreter but not initialized with a value, so it actually logs undefined instead.

Another weird case:

var a = 1;
d = 3;
console.log(a + ' ' + d);
var d;

Since the declaration of d (var d;) is "hoisted" above the assignment (d = 3;), this actually does not throw any errors and logs 3.

Hoisting Functions

The hoisting of functions is similar to variable hoisting, in that the declaration of any named functions will be "hoisted". However, what makes functions different in this is that their definition will be hoisted as well as their declaration.

In general, you do not want to hoist any functions within the browser unless you have a good reason, since it costs a lot of extra memory for the browser. This can be avoided by using anonymous functions as opposed to named functions like below:

// Outputs: "Definition hoisted!"
definitionHoisted();

// TypeError: undefined is not a function
definitionNotHoisted();

// named function
function definitionHoisted() {
    console.log("Definition hoisted!");
}

// anonymous function
var definitionNotHoisted = function () {
    console.log("Definition not hoisted!");
};

References:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
  2. https://www.udemy.com/course/modern-javascript-from-the-beginning/learn/lecture/8757146#overview
  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
  4. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
  5. http://www.ecma-international.org/ecma-262/6.0/index.html
  6. https://www.youtube.com/watch?v=ppMlvGMT2qE
  7. https://stackoverflow.com/questions/15005098/why-does-javascript-hoist-variables
  8. http://adripofjavascript.com/blog/drips/variable-and-function-hoisting.html

Last modified: 202106291355

Event Listeners (Javascript)

Event listeners in Javascript run a function on the emitting of an event, including click, keyup, resize, and more.

element.addEventListener('eventType', function(e) {
  // do something
});

This adds a listener to whatever element it is attached to. It waits for the 'event' to occur, and once it does, it calls the callback function. The e (short for event)is the callback object, which can give you information on the event and its related elements.

One can also pass in a named function instead of use an anonymous one. This can lead to cleaner code, as it is more declarative than imperative

element.addEventListener('event', onClick);

function onClick(e){
  // do something
};

There is a third Boolean parameter of addEventListener that specifies if you want the handler to fire on capture or bubble. It defaults to false, which is bubble. But if you set it to true, it will fire on capture.

The Event Object

The e that is in the functions pertaining to eventListener's in Javascript is the object that is returned by a specific event with many parameters like the coordinates of the click, the element clicked, etc. If you have an eventListener attached to a certain element that will trigger on a click, then when the user clicks, it will return an event object. This event object is what gets passed as e into the function.

e.target is used to specify the element on which you clicked.

Event Bubbling and Delegation

Event bubbling is where an event listener attached to a certain element will be triggered by a child element. This is because of the elements being nested within each other. If div2 is nested within div1, a trigger on div2, will also trigger div1, since div2 is nested within div1.

Event delegation is a pattern where an event listener attached to an element is not triggered unless a specified child element is the trigger. This is useful if there are many elements that have the same class name or ID and you want an action done to a specific one. It is done through if statements on the callback specifying attributes like class name or id.

<div id="outer">
  <div id="inner-1">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  </div>
  <div id="inner-2">No</div>
</div>
// This will fire on any click that happens on it or any of its child elements (bubbling to the top component)
document.getElementById('outer').addEventListener('click', () => {
  console.log('bubbled');
});

// This will fire only when a specific child or any of its children are clicked (delegated to specific children)
document.getElementById('outer').addEvenetListener('click', () => {
  const innerOne = event.target.closest('#inner-1');
  if (innerOne) {
    console.log('delegated');
  }
});

Most Common Event Types

  • blur - The event occurs when an element loses focus
  • change - The event occurs when the content of a form element, the selection, or the checked state have changed (for <input>, <select>, and <textarea>)
  • click
  • DOMContentLoaded - The event occurs when the HTML has been fully parsed and loaded.
  • focus
  • keydown/keyup
  • keypress
  • mousedown/mouseup
  • mouseenter/mouseleave/mousemove/mouseover/mouseout/mouseup
  • submit - The event occurs when a form is submitted

References:

  1. https://www.udemy.com/course/modern-javascript-from-the-beginning/learn/lecture/8757278#content
  2. https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
  3. https://stackoverflow.com/questions/35936365/what-exactly-is-the-parameter-e-event-and-why-pass-it-to-javascript-functions
  4. https://www.udemy.com/course/modern-javascript-from-the-beginning/learn/lecture/8762202#content
  5. https://www.udemy.com/course/modern-javascript-from-the-beginning/learn/lecture/8757286#content
  6. https://www.w3schools.com/jsref/dom_obj_event.asp

Last modified: 202110021724

Date (Javascript)

Javascript Date objects have some weird intricacies that need attention.

Time Zones

JavaScript's Date object tracks time in UTC internally, but typically accepts input and produces output in the local time of the computer it's running on. The way to mitigate this (IMO undesired) opinion is two options.

// will change time based on computer's time zone
var myBirthday = ('January 1, 1990');

UNIX Timestamp

If you use a website like unixtimestamp.com, you can convert your times beforehand and using these as input, will always produce the correct time regardless of timezone.

var myBirthday = ('631180800');

Specify GMT+0:00 Time Zone

When inputting a more human-readable datetime stamp, follow it with GMT+0:00 and this will force a normalized timezone, regardless of the computer's settings.

var myBirthday = ('January 1, 1990 GMT+0:00');

References

Last modified: 202108191820

Mocha and Chai (Javascript)

Mocha is a Javascript test framework for use with Node, and Chai is an assertion library.

Another common library to use with Mocha is nyc, which allows you to get a code coverage readout. You can use this by npm i nyc and then adding it to your package.json as a script: "coverage": "nyc npm run test".

Quick Start

Install Mocha and Chai using npm i --save-dev mocha chai.

In your package.json, replace the value of the "test" property within "scripts" with "mocha ./path/to/tests", inserting the path to your tests.

Create a file called example.js within your test folder. Place this inside:

const assert = require('chai').assert;

describe('Sum', () => {
  it('should add 2 and 2 to equal 4', () => {
    assert.equal(2 + 2, 4);
  });
});

Save this file and in your terminal, run npm run test. This should render a screen showing a test, "should add 2 and 2 to equal 4", passing within the "Sum" section.

Assert

All are assumed to start with assert.

Comparison

Invoked with (actual, expected).

Chain Effect
.equal, .notEqual Non-strict equality (==)
.deepEqual, .notDeepEqual Strict equality (===), also used for objects

Simple

All are accompanied with a negative assertion, e.g. .isX/ .isNotX.

  • .exists(x)
  • .include([x,y,z], x)
  • .deepInclude([obj1, obj2], obj1)
  • Every primitive (.isNumber, .isBoolean, isTrue, etc.)

Asynchronous Tests

References

  1. https://mochajs.org/
  2. https://www.chaijs.com/
  3. https://www.chaijs.com/api/assert/
  4. https://gist.github.com/yoavniran/1e3b0162e1545055429e#jest
  5. https://www.testim.io/blog/testing-promises-using-mocha/

Last modified: 202107230513

Typescript

Typescript is a superset of Javascript that is strongly typed and values specificity.

Casting

You can cast one type as another in a couple different ways.

// In these examples, query selector will naturally return an HTMLElement. To 
// access the `value`, we will need to cast it as an HTMLInputElement.

let input;

// using 'as'
input = document.querySelector('input[type="text"]') as HTMLInputElement;

// using <>
input = <HTMLInputElement>document.querySelector('input[type="text"]');

When using TypeScript with JSX, only as-style assertions are allowed.

Type Annotations

Type annotations are done at the declaration of a variable with a colon followed by the type or interface.

// Primitives
const greeting: string = "Hello there!";

// Arrays
const numbers: number[] = [1, 2, 3, 4];

// Generics
const uniqueCharacters: Set<string> = new Set(['a', 'b', 'c']);

// Interfaces/Types
interface Person {
  name: string,
  age: number,
  sayHi: () => string,
}
const johnSmith: Person = {
  name: "John Smith",
  age: 40,
  sayHi: () => return greeting;
};

// Functions
//           Param Types            Output type
const add = (a: number, b: number): number => {
  return a + b;
};

Annotations with Object Destructuring

// without annotation
const getNameAndAge = ({ person, job }) => {
  const {
    name,
    age,
  } = person;
  return `${name}: ${age}, ${job}`;
};

// with annotation
const getNameAndAge = 
      ({ person, job }: { person: { name: string, age: number }, job: string }) => {
  const {
    name: string,
    age: number,
  } = person;
  return `${name}: ${age}, ${job}`;
};

// with type or interface
type Person = {
  name: string,
  age: number
};

const getNameAndAge = ({ person: Person, job: string }) => {
  const {
    name: string,
    age: number,
  } = person;
  return `${name}: ${age}, ${job}`;
};

Using any

In general, you want to avoid using any as a type. ESLint has it disallowed by default, since it defeats the purpose of Typescript altogether. But what do you do if you actually don't know what data you will be receiving?

The issue is that using any will allow a false sense of security with TypeScript, as any types will allow compilation but sometimes will fail in the actual execution of the application, which is exactly what we don't want.

The solution here is to use the unknown type. This will not allow compilation and will enforce the strict typing that makes TypeScript what it is and not JavaScript.

NOTE: My personal opinion is that you should always strive to find out what your data is that is going through your system, and if a type or interface does not exist for your own objects or with an external library you are using, one should be created to accommodate. Though I understand this is not always possible, it should be strived for.

Typing React

onChange Events

For React onChange handlers, you can use the React.ChangeEvent<> generic, filling it in with whatever type of element is being changed.

<input
  onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
    handleEmail(event);
    handleEmailValidation();
  }}
  placeholder="Enter Email"
  type='email'
/>

Unique Typing Troubleshooting

Property '***' does not exist on type 'never'

This means that the target variable has not ben typed correctly and often will show up when something has not been given a type at all.

// incorrect
const thing = 'Oh yeah!';
const things = [1,2,3,4];
const specificThing = { name: 'John', age: 9 };
// correct
const thing: string = 'Oh yeah!';
const things: number[] = [1,2,3,4];
const specificThing: InterfaceName = { name: 'John', age: 9 };

useState

With useState in React hooks, you will need to use a special syntax in creation of the hooks themselves. Since useState is a generic function, the typing happens within the <> characters.

type HashtagListener {
  ...
}

const [editedHashtagListeners, setEditedHashtagListeners] = useState<HashtagListener[]>([]);

Interface and Type

Interfaces and types are two ways to define a type of object, declaring the types of the contained properties.

Differences

Type

// Basic objects

type Person = {
  name: string,
  age: number,
  pets: string[]
};

const john: Person = {
  name: 'John',
  age: 40,
  pets: ['Mary', 'Doug']
};

const household: Person[] = [john];

// Using list of specific keys

type AllowedKeys = 'name' | 'age';

type Person = Record<AllowedKeys, unknown>;

const Human: Person = {
  name: 'Steve',
  age: 42,
};

Interface

interface Person {
  name: string,
  age: number,
  pets: string[]
};

const john: Person = {
  name: 'John',
  age: 40,
  pets: ['Mary', 'Doug']
};

const household: Person[] = [john];

Creating Fixed Values

type Roles = 'owner' | 'admin';

interface User {
  name: string;
  // value must be an array containing values within Roles
  roles: Roles[];
}

Defining Unknown Property Keys

type Roles = 'owner' | 'admin';

interface User {
  name: string;
  channels: {
    // channel at `index` must be a string
    // value must be an array containing values within Roles
    [index: string]: Roles[];
  }  
}

References:

  1. https://stackoverflow.com/questions/52423842/what-is-not-assignable-to-parameter-of-type-never-error-in-typescript
  2. https://stackoverflow.com/questions/53598449/react-hooks-and-typescript-property-does-not-exist-on-type-never
  3. https://stackoverflow.com/questions/41443242/how-to-correct-flow-warning-destructuring-missing-annotation
  4. https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces
  5. https://lzomedia.com/blog/how-to-apply-type-annotations-to-functions-in-typescript/
  6. https://stackoverflow.com/questions/12989741/the-property-value-does-not-exist-on-value-of-type-htmlelement
  7. https://stackoverflow.com/questions/61851004/describe-interface-fixed-values-in-array-element-of-typescript
  8. https://stackoverflow.com/questions/23914271/typescript-interface-definition-with-an-unknown-property-key
  9. https://basarat.gitbook.io/typescript/type-system
  10. https://dev.to/mattzgg_94/get-started-with-using-typescript-and-tdd-to-solve-leetcode-problems-in-vs-code-26d
  11. https://www.udemy.com/course/understanding-typescript/
  12. https://stackoverflow.com/questions/33256274/typesafe-select-onchange-event-using-reactjs-and-typescript
  13. https://www.cstrnt.dev/blog/three-typescript-tricks
Backlinks

Last modified: 202110122126

ESLint

Enforce rules and raise warnings to keep your Javascript, Typescript, and React code clean and bug free.

Ignore rule in a file

By placing this at the top of the file, it will ignore this rule throughout the entire file. /* eslint-disable {rule} */

To disable a rule for only one line, place this after the code on the offending line. // eslint-disable-line {rule}

Backlinks

Last modified: 202107291557

HTTP

There's currently nothing here.

Backlinks

AJAX

AJAX stands for Asynchronous Javascript And XML. It is an asynchronous way to get and send data. Usually used with JSON. AJAX is built in to Javascript.

When an AJAX call is made in your Javascript code, the AJAX engine takes your request and converts it into a proper XmlHttpRequest. The website that is being queried then responds (with JSON or XML) and the AJAX engine then converts it into an HTML response that can be parsed by Javascript.

Ajax is able to asynchronously handle HTTP requests and responses, interpreting the requests from JS to HTTP and responses from JSON to HTML responses. This allows a fluid application that doesn't need to refresh the browser to function.

A standard implementation of AJAX involves these steps:

  1. Creating the XHR object
  2. Defining the request parameters
  3. Instructions on a successful and unsuccessful request
  4. Sending/starting the request

XMLHttpRequest (XHR Object)

XMLHttpRequest is an API that is in the form of an object, with methods and properties attached. When a request is made and when a response is received, all of that work goes on behind the scenes and this object is updated as things happen.

To use the XHR object, a new instance needs to be created and assigned to a variable.

var xhr = new XMLHttpRequest();

.open()

.open() is an XHR function that takes three parameters: type of request, URL or file name, and a boolean of whether it is asynchronous or not.

xhr.open('GET', 'https://www.requestURL.com', true);

.onreadystatechange

You define a function at that property, and it will run every time the readyState property of the XHR object changes. The readyState values are:

  • 0 - Request not initialized
  • 1 - server connection established
  • 2 - request received
  • 3 - processing request
  • 4 - request finished and response is ready
xhr.onreadystatechange = function () {
  // if the readyState property of the XHR object ('xhr') is 4
  // AND the status in the XHR object is 'OK'
  if (this.readystatechange == 4 && this.status === 200) {
    // get the responseText from the XHR object ('xhr')
    console.log(this.responseText)
  }
}

.onprogress

.onprogress is a property that holds a function, defined by the developer, that will be called once the readyState is at 3, when the request is being processed.

xhr.onprogres = function () {
  // Show the loading image or something that denotes waiting  
}

.onload / .onerror

.onload and .onerror are properties that hold functions, defined by the developer, that will be called once the readyState is at 4, when the request is finished and response is ready, or when an error is detected.

xhr.onload = function () {
  // if the status in the XHR object (xhr) is 'OK'
  if (this.status === 200) {
    // get the responseText from the XHR object ('xhr')
    console.log(this.responseText)
  }
};

xhr.onerror = function () {
  console.log('Request error');
};

.setRequestHeader()

When making a POST request, you will need to set the request header. This function takes two parameters: the name of the header and the value it will have. This can be called multiple times in a row to set multiple parameters, and they will all be compiled together to one header. Learn more about HTTP headers here.

xhr.setRequestHeader('Content-type', 'application/json');

.send()

This will send the request that has already been created by .open(). The body of the request should be passed in as a parameter, but it is optional, like in a simple GET request.

xhr.send();

Response Data Types

All of the previous examples have been for if you are making a request for a plaintext file, by getting the responseText property from the XHR object. If your response ends up being a JSON file, you can parse this with JSON.parse(this.responseText).

Libraries


References

  1. https://www.youtube.com/watch?v=82hnvUYY6QA
  2. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

Last modified: 202107020539

Regular Expressions (Javascript)

In Javascript, regular expressions are enclosed within two forward slashes and flags are placed oustide.

let re = /hello/m;  // or
let re = new RegExp('hello', 'm');

Methods

.exec() / .match()

re.exec(item) and item.match(re) will search for the regex (re) inside of item. If found, this returns the expression, the index of beginning of match, and the input item. if not found, this returns null.

.replace()

item.replace(re, replacement) will replace instances of regex (re) with replacement and return the modified item.

.search()

item.search(re) returns index of first found instance of reg ex in item. if not found, returns -1.

.source()

re.source returns the reg expression without the slashes, re being a variable holding a regular expression.

let re = /hello/m;
console.log(re.source); // "hello"

.split()

item.split(re) returns an array of the string split by the regex.

var myString = 'Hello 1 word. Sentence number 2.';
var splits = myString.split(/(\d)/);
// returns [ "Hello ", "1", " word. Sentence number ", "2", "." ]

.test()

re.test(item) returns boolean of if regex is found in item.

let re = /hello/m;
re.test('hello world!') // returns true
re.test('me first') // returns false

References

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split

Last modified: 202107020550

NVM

Node Version Manager allows you to use multiple diferent versions of node and switch between them easily.

Installation

NVM

Install the newest version of NVM (get the current version number here)

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash

Be sure to completely restart your terminal before proceeding.

Node

$ nvm install --lts # most recent version with long term support
$ nvm install node  # most recent version without LTS

Usage

$ nvm use --lts
$ nvm use node

Specific Versions

$ nvm ls                # show all installed versions
$ nvm install xx.xx.x   # x's meaning the version numbers
$ nvm use xx.xx.x
$ nvm uninstall xx.xx.x

Set Default Node Version

$ nvm alias default xx.xx

Within a Project

Create a file in the root of your project called .nvmrc and place the version number inside, e.g.

14.17.6

To use nvm within the project, set your current directory to the root of the project where the .nvmrc file is and follow these steps:

  • nvm use to use the specified version
  • nvm install the version, if needed

References

  1. https://techstacker.com/run-multiple-node-versions-node-nvm/
  2. https://github.com/nvm-sh/nvm#installing-and-updating
  3. https://stackoverflow.com/questions/57110542/how-to-write-a-nvmrc-file-which-automatically-change-node-version

Last modified: 202109110517

React Hooks

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks allow the simplicity of functional components with the complexity and flexibility of class components.

These examples are using Typescript for type annotations and clarity.

useContext

useContext is a way to pass global state values around to different components by wrapping components within a provider and then invoking the consumer in the necessary components.

In its most basic form (taken from Dave Ceddia):

import React, { createContext } from 'react';

// Create a Context
const NumberContext = createContext();
// It returns an object with 2 values:
// { Provider, Consumer }

const App = () => {
  // Use the Provider to make a value available to all
  // children and grandchildren
  return (
    <NumberContext.Provider value={42}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
};

const Display = () => {
  // Use the Consumer to grab the value from context
  // Notice this component didn't get any props!
  return (
    <NumberContext.Consumer>
      {value => <div>The answer is {value}.</div>}
    </NumberContext.Consumer>
  );
};

However, instead of using the Consumer wrapper, you can use useContext and destructure the variables held within:

import React, { createContext, useContext } from 'react';

const NumberContext = createContext();

const App = () => {
  return (
    <NumberContext.Provider value={42}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
};

const Display = () => {
  const { value } => useContext(NumberContext);
  return <div>The answer is {value}.</div>;
};

This becomes more and more useful when multiple contexts are used and you can end up with wrappers over wrappers over wrappers and it gets real unwieldy really quick.

Simplifying a Global Context

If one is using many different contexts over all components, these different contexts can be placed into individual files and imported into a 'main' context file that exports a higher order function which wraps any children in these different contexts.

contexts/ExampleContext.jsx (same thing for contexts/AnotherContext.jsx)

import { createContext } from 'react';
import { Channel } from '../types/types';


export interface ExampleContextInformation {
  name: string;
  age: number;
  setName: Function;
  setAge: Function;
}

// Fill this in with the default values. We will redefine the setters
// once in the component where this is used.
export const ExampleContext = createContext<ExampleContextInformation>({ 
  name: '',
  age: null,
  setName: () => {},
  setAge: () => {},
});

contexts/GlobalContext.jsx

import React from 'react';

import { ExampleContext, ExampleContextInformation } from './ExampleContext';
import { AnotherContext, AnotherContextInformation } from './AnotherContext';

interface GlobalProps { 
  exampleContextObject: ExampleContextInformation, 
  anotherContextObject: AnotherContextInformation,
}

export function GlobalContext(props: any) {
  const {
    exampleContextObject,
    anotherContextObject
  }: GlobalProps = props;

  return (
    <ExampleContext.Provider value={channelContextObject}>
      <AnotherContext.Provider value={userContextObject}>
        {props.children}
      </AnotherContext.Provider>
    </ExampleContext.Provider>
  );
}

App.jsx

import React, { useState } from 'react';

import { GlobalContext } from './contexts/GlobalContext';
import { ExampleContextInformation } from './ExampleContext';
import { AnotherContextInformation } from './AnotherContext';

export default function App() {
  const [name, setName] = useState<string>('');
  const [age, setAge] = useState<number | null>('');
  const [anotherVar, setAnotherVar] = useState<number>(0);

  const exampleContextObject: ExampleContextInformation = {
    name,
    age,
    setName: (name: string) => setName(name),
    setAge: (age: number) => setAge(age),
  };

  const anotherContextObject: AnotherContextInformation = {
    anotherVar,
    setAnotherVar: (anotherVar: number) => setAnotherVar(anotherVar),
  }

  return (
    <GlobalContext
      exampleContextObject={exampleContextObject}
      anotherContextObject={anotherContextObject}
     >
      {/* Components in here have access to contexts via useContext */}
      <ChildComponent />
    </GlobalContext>
  )
}

ChildComponent.jsx

import React, { useContext } from 'react';
import { ExampleContext } from './ExampleContext';
import { AnotherContext } from './AnotherContext';

export default function ChildComponent() {
  const { age, setAge } = useContext(ExampleContext);
  const { anotherVar } = useContext(AnotherContext);

  return (
    <div>
      <p>Your age is {age} and this is {anotherVar}!</p>
      <button type="button" onClick={() => setAge(Date.now())}></button>
    </div>
  )
}

useEffect

useEffect lets you perform side effects on useState changes, effectively replacing componentDidMount and componentDidUpdate.

import React, { useEffect } from 'react';

const testComponent = () => {
  ...

  // this will run on every rerender (generally don't want this)
  useEffect(() => {
    // do stuff
  });

  // this will run the function once on mount
  useEffect(() => {
    // do stuff
  }, []);

  // this will run anytime that variable `names` is changed
  useEffect(() => {
    // do stuff
  }, [names]);

  ...

useState

useState lets you use state within a functional component.

NOTE: useState does not have a callback as second argument, like the normal setState invocation does. Use useEffect to handle side effects and changes on state updates.

import React, { useState } from 'react';

interface Name {
  first: string,
  last: string,
}

const testComponent = () => {  
  // this will create a getter and setter for state variable `names`
  const [counter, setCounter] = useState<number>(0);
  const [names, setNames] = useState<Name[]>([]);

  // sets counter 
  const onClick = () => {
    setCounter(counter + 1);
  };

  const onSubmit = (firstName, lastName) => {
    setNames([
      ...names,
      {
        first: firstName,
        last: lastName
      }
    ]);
  }  

  ...

References

  1. https://reactjs.org/docs/context.html#dynamic-context
  2. https://daveceddia.com/usecontext-hook/

Last modified: 202110081542

React from Scratch

Learn how React works by building it without the create-react-app framework.

For React to work properly, you will need three things:

  • Babel - This is a transpiler that will allow you to use JSX within your components and make your site usable to clients that do not have ES6 functionality available.
  • Webpack - This is a compiler that will take all of your modules, styles, etc. and put them together.
  • React - This is the meat and potatoes that will render your page, let you use state, hooks, etc.

The easiest way to do this is with create-react-app. But if you want to know how it works:

Get all your parts

  • Initialize a new npm project with npm init. You can skip all the questions with the -y flag.

  • Install babel in your development dependencies: npm install --save-dev @babel/core @babel/preset-env @babel/preset-react.

    • @babel/core — This contains the babel core configuration,
    • @babel/preset-env — This contains different plugins, the most important of which transforms all ES2015-ES2020 code to be ES5 compatible (the one JavaScript version where almost all browsers implement)
    • @babel/preset-react — This contains different plugins to enable React syntax parsing and transformation.
  • Install babel-loader for webpack to use: npm install --save-dev babel-loader

    • To transform our code, we will use a package called babel-loader. babel-loader will allow us to transpile our JavaScript file using babel and webpack.
  • Install webpack in your development dependencies: npm install --save-dev webpack webpack-cli webpack-dev-server

    • webpack — the core webpack functionality package.
    • webpack-cli — this package is necessary to use the CLI.
    • webpack-dev-server — this is for the dev server that allows live reloading
  • Install react in your project. npm install react react-dom

  • Create the public-facing folder for the client, and an app.js within a sibling src folder

Make your webpack config and babel config

In the root folder, create a webpack.config.js file that pulls in the node path module. This is where you will be putting your entry and output points in your webpack builders. (TA: Search 'webpack configuration' and you should be reminded of all the things you need.)

const path = require('path');

module.exports = {
  entry: '.src/app.js',     // which file your app will be pulling the data from for it's dependency graph
  output: {
    filename: 'bundle.js',  // the name of the file it will output the bundle to
    path: path.join(__dirname, 'public'),  // the output folder fo your bundles
  },
  module: {  // determines which loader to use
    rules: [{
      loader: 'babel-loader',
      test: /\.jsx?$/,            // transform js files
      exclude: /node_modules/,  // but not node_modules
    }]
  },
  devServer: {
    contentBase: path.join(__dirname, 'public'), // where to serve from when running the webpack dev server
  }
}

In the root folder, create a file called babel.config.json. (TA: Search for 'babel config' and you should be able to find everything you need.)

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

babel-loader will try to find the babel configuration file —this babel.config.json. The code in this file instructs babel-loader to use @babel/preset-env and @babel/preset-react presets that we have installed earlier when transpiling our code.

Add scripts in package.json for running webpack

"scripts": {
  "build": "webpack",
  "start": "webpack serve", 
  "watch": "webpack --watch"
}

Create your documents

In public, make the html page you will inject into. This needs to have the injection point as well as the webpack bundle.

<!doctype html>
<html>
  <head>
    <title>Test</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

In src, create the React JS page that will inject your app into the root div.

import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
  return (
    <div>
      <h1>Wow! This is some stuff.</h1>
    </div>
  )
}

ReactDOM.render(
  <App />, 
  document.getElementById('root')
);

Test it out by running npm run start and checking it in a browser.

References

  1. https://medium.com/swlh/back-to-basics-how-to-set-up-a-react-app-from-scratch-2020-134908e17490
Backlinks

Last modified: 202107081809

React Router

React Router is a way to link to other pages dynamically within your React single page application.

All of these examples were pulled straight from the docs.

Installation

npm install react-router-dom

Usage

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        {/* A <Switch> looks through its children <Route>s and
            renders the first one that matches the current URL. */}
        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Users() {
  return <h2>Users</h2>;
}

Nested Routing

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useRouteMatch,
  useParams
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/topics">Topics</Link>
          </li>
        </ul>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/topics">
            <Topics />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Topics() {
  let match = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>

      <ul>
        <li>
          <Link to={`${match.url}/components`}>Components</Link>
        </li>
        <li>
          <Link to={`${match.url}/props-v-state`}>
            Props v. State
          </Link>
        </li>
      </ul>

      {/* The Topics page has its own <Switch> with more routes
          that build on the /topics URL path. You can think of the
          2nd <Route> here as an "index" page for all topics, or
          the page that is shown when no topic is selected */}
      <Switch>
        <Route path={`${match.path}/:topicId`}>
          <Topic />
        </Route>
        <Route path={match.path}>
          <h3>Please select a topic.</h3>
        </Route>
      </Switch>
    </div>
  );
}

function Topic() {
  let { topicId } = useParams();
  return <h3>Requested topic ID: {topicId}</h3>;
}

References

  1. https://github.com/ReactTraining/react-router

  2. https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/philosophy.md

Last modified: 202107081858

JSX

There's currently nothing here.

Backlinks

C

C is a programming language that is very low-level, compiling down to assembly language.

Hello, World

Code

Create a new file called helloworld.c and add this to the contents:

#include <stdio.h>  /* Imports the standard library for IO */

main()  /* defines the function main containing no parameters */
{
    printf("hello, world\n"); /* prints "hello, world" in stdio */
    /* note that the newline must be placed deliberately. C does */
    /* not add a newline with print like Python does. */
}

Compile

Then you want to compile it. The basic compiler found on UNIX computers is cc. Compile it by typing cc helloworld.c. This will create a file called a.out, which is the compiled version of your helloworld.c.

Run It

Run this by typing ./a.out in your shell. You should see hello, world in your terminal.

Basics

Comments

// Single line comment
/* Multiline
   comment */

Constants

Symbolic Constants

Symbolic constants allow the developer to avoid magic numbers and add semantically useful labels to values. This is done using he syntax #define NAME value.

#include <stdio.h>
#define TAXRATE 0.09
#define SERVICECHARGE 2

main()
{
  printf("The tax rate is %1.2f and the service charge is %d", TAXRATE, SERVICECHARGE);
}

/* prints "The tax rate is 0.09 and the service charge is 2"

These statements don't actually do anything in the code. They are handled by the preprocessor and the references to the NAME are simply replaced by the corrseponding value when found. So the above printf line, when eventually seen by the compiler, will be:

printf("The tax rate is %1.2f and the service charge is %d", 0.09, 2);

Enumeration Constants

An enumeration constant is a list of constant integer values. They will start at 0, incrementing on each new constant, unless otherwise defined.

enum boolean { FALSE, TRUE }; // FALSE == 0, TRUE == 1
enum months { JAN = 1, FEB, MAR, ...}; // JAN == 1, FEB == 2...
enum fib { FIRST = 1, SECOND = 1, THIRD,
           FOURTH, FIFTH = 5, SIXTH = 8 } // THIRD == 2, FOURTH == 3...

These constants can be used the same as symbolic constants.

Variables

Variables must be declared before they are used, usually at the beginning before executing your program. They are declared by type and then by name.

int num, step;
char letter;

Variables that exist in and only within a given function are called automatic variables. They come into existence only when the function begins and disappear when the function is finished.

The const keyword may be added to any variable declaration. This means that the variable declared will not change throughout its usage.

External Variables

External variables are defined exactly once outside of any function. This is so that the computer can set aside storage. Within each function that will use that, you will need to declare that variable, and preface that declaration with extern. For instance if max is an external variable, you would declare it within the function as extern int max.

If multiple source files are used, for instance defining X in one file and wanting to use it in another file, the extern declaration is required. If it is all in one file, they can be omitted.

Common practice is to define all external variables in a header file with a .h extension and then #include it in your source files.

Libraries

stdio.h

printf(string, [format, ...])

If you use a format tag in the string, like %d or %c, you will need to add what will replace it in the list of format variables.

int fahr, celsius;
fahr = 100;
celsius = 37;
printf("%d F = %d C", fahr, celsius);
/* prints "100 F = 37 C" */

The format tags can also be accompanied by the minimum width of characters printed.

printf("%3d F = %3d C", fahr, celsius); /* prints "100 F = 37  C" */
printf("%2d F = %2d C", fahr, celsius); /* prints "100 F = 37 C" */

getchar(), putchar(x)

getchar will resolve to a character from stdin, and putchar(x) will put the value of x in stdout.

Sandboxing

You can send text via stdin using printf "123xyz" | ./program.out, with program.out being the name of the compiled program.

You can also use an online REPL, like replit.com.

References

  1. https://hikage.freeshell.org/books/theCprogrammingLanguage.pdf
  2. https://stackoverflow.com/questions/19379353/symbolic-constants-in-c-define-statement
Backlinks

Last modified: 202108011853

Functions (C)

Basics

Here is the structure of a function definition in C.

/*
return-type function-name(parameter declarations, if any)
{
  declarations
  statements
}
*/

// An example

int add(int m, int n)
{
  int sum;
  sum = m + n;
  return sum;
}

main()

main is a special function that will begin executing when running your compiled file. This must be named main, but other functions can take on whatever other names you'd like.

When a function is invoked within the main function, a function prototype is required to ensure that all invocations and definitions match up.

#include <stdio.h>

int add(int m, int n);
int hooray(void);       // if no params, void is used

int main()
{
  int i;

  for (i = 0; i < 10; ++i)
      printf("%d %d %d\n", i, add(2,i), add(-3,i));
      hooray()
  return 0;
}

int add(int m, int n)
{
  int sum;
  sum = m + n;
  return sum;
}

int hooray()
{
  printf("Hooray!");
}

Last modified: 202107211457

Arrays (C)

Arrays in C, like all things in C, require a lot more care than higher level languages.

Initialization

Arrays are intialized as normal, but followed by n items that should reside in the array: int numbers[n].

You can set the values of each of these items with curly braces.

int array[5] = { 1, 2, 3, 4, 5 };
int zeroArray[10] = { 0 };

In an array of integers, if the list of values within the curly braces is less than the amount needed to fill it completely, all remaining values will resort to zero. Meaning that you can instantiate an array of integers with 0 via int array[n] = { 0 }.

Access/Modification

Arrays can be accessed or modified as normal via square brackets.

int array[8] = { 0 };

array[0] = 100;
array[4] = 500;

Information

Size/Length

The size or length of an array needs some calculation. The built in sizeof function will return the size of an array in bytes, which is not particularly helpful unless you know the size of each cell. So you can use the sizeof function to get the size of the first cell and divide the total size by that value.

#include <stdio.h>

int main() 
{
    int total, single, len;
    int array[10];

    total = sizeof(array);
    single = sizeof(array[0]);
    len = total / single;

    printf("total: %d, single: %d,len: %d", total, single, len);
    // total: 40, single: 4, len: 10

    return 0;
}

Integers that are passed in as arguments will not be able to utilize this technique. The length will need to be calculated ahead of time and passed in as another argument.

#include <stdio.h>

void reverse(char str[], int len);

int main() 
{
    int total, single, len;
    char array[] = "hello";

    total = sizeof(array);
    single = sizeof(array[0]);
    len = total / single;
    printf("%d, %d, %d\n", total, single, len);

    reverse(array, len);

    return 0;
}

void reverse(char str[], int len)
{
  int i;

  for (i = len - 1; i >= 0; i--)
    printf("%c", str[i]);
}

References

  1. https://stackoverflow.com/questions/201101/how-to-initialize-all-members-of-an-array-to-the-same-value
Backlinks

Last modified: 202107182334

C Data Types

The different data types in C all have their own characteristics.

Since C is strongly typed, certain actions that are intuitive in Javascript or Python may not yield the results you wanted. For instance, if you have variable int x and you try and initialize it with a fractional number, the fractional part will be discarded since x stores an int.

Arrays are intialized as normal, but followed by n items that should reside in the array: int numbers[n].

The following list is only what I've used most and by no means a complete list. Look at the Wikipedia page for more info.

Type Bits Limits Format Description
char 8 -127, +127 %c Used for characters within strings (array of chars)
signed short int 16 -32,767, +32,767 %i Used for numbers and traversing data from stdin
unsigned short int 16 0, +65,535 %u
signed int 16 -2,147,483,648, +2,147,483,647 %i
unsigned int 32 0, +4,294,967,295 %i
signed long int 64 -9,223,372,036,854,775,808, +9,223,372,036,854,775,807 %li
unsigned long int 64 0, +18,446,744,073,709,551,615 %lu
float 32 n/a %f Use for floating point numbers
double 64 n/a %lf Use for really long floating point numbers

Signed/Unsigned

Unsigned numbers are always zero or higher and will have a range of 0 to (2^n) - 1. Signed numbers are negative or positive and have a range of -(2^n-1) to (2^n-1) - 1.

Int

int's can be short or long. Each processor has their own limitations they will choose, but short is always smaller than long, short must be at least 16 bits, and long must be at least 32 bits. It is usually the case that short is 16 bits and long is 32 bits, but the real value on your processor can be found as symbolic constants within the <limits.h> header.

int values can be represented as standard decimal (123), octal (0173), or as hexadecimal (0x7B).

Float

The type long double represents extended-precision floating point. The processor decides the final size of floats and the real values can be found as symbolic constants within the <float.h> header.

References

Last modified: 202108011853

Strings (C)

Strings in C are arrays of characters.

Basics

Both of these strings are arrays of 6 characters in length. These two are the same:

char str1[] = "Hello";
char str2[] = {'H', 'e', 'l', 'l', 'o', '\0'};

Length

The length of a C string is determined by searching for the null termination character, \0.

Syntax

/0

This is the null termination character, signifying the end of the string within the string array.

References

  1. https://stackoverflow.com/questions/14461695/what-does-0-stand-for
  2. https://en.wikipedia.org/wiki/C_string_handling

Last modified: 202107182014

gitignore

Creating a .gitignore file in the root folder of your project will ensure every file that matches a line within the file will be ignored by git.

  • Using a * will work as a wildcard for every file within that level of the given directory, or as a wildcard within a filename.
  • Using two ** in the filepath will look within every level recursively from that point forward. e.g. **/.DS_Store will find a file called .DS_Store in the root directory as well as any others in any folders within that root directory. lib/**/__pycache__ will match any files or folders named __pycache__ that are within the lib directory at any depth.

Global gitignore

You can ignore files globally by adding them to ~/.gitignore_global.

Delete previous files in gitignore

If you add a file to .gitignore after previously committing that file, you may see untracked changes on those files. You have to remove the old files from the git repository to remove that error.

  • Remove the existing files: find . -name {filename} -print0 | xargs -0 git rm -f --ignore-unmatch
  • Add the file to the gitignore: {filename}

References

  1. https://stackoverflow.com/questions/107701/how-can-i-remove-ds-store-files-from-a-git-repository
  2. https://git-scm.com/docs/gitignore

Last modified: 202110141545

My git Aliases

This is a list of all of my current aliases I use with git. This is an output of my git alias command, which you will see below. Learn how to set these in the git page.

a = add
aa = add .
alias = ! git config --get-regexp ^alias\. | sed -e s/^alias\.// -e s/\ /\ =\ /
ap = add -p
b = branch
bd = branch -d
bD = branch -D
co = checkout
cb = checkout -b
ci = commit
cm = commit -m
ca = commit --amend
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
pu = push origin HEAD
pl = pull origin HEAD
s = status
st = status

References

Backlinks

Last modified: 202109251415

git alias

You can check out my personal list of git aliases here.

Command Action
--global alias.{name} Set the alias name across your whole machine
--unset alias.{name} Unset the following alias
--unset-all alias.{name} Unset all of the aliases found at the following alias (useful if you accidentally set two aliases on the same name)
shell> git config --global alias.co checkout # now 'git co' is aliased to 'git checkout'
shell> git config alias.p 'push origin HEAD'  # now 'git p' is aliased to 'git push origin HEAD' ONLY for current project
shell> git config --global --unset alias.p # now 'git p' is no longer aliased

List All Aliases

Running this will give you the git alias command, which will list all of your current git aliases.

$ git config --global alias.alias "! git config --get-regexp ^alias\. | sed -e s/^alias\.// -e s/\ /\ =\ /"

References

  1. https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
  2. https://koukia.ca/delete-a-local-and-a-remote-git-branch-61df0b10d323
  3. https://bugfactory.io/blog/orphaned-brachnes-in-git/
  4. https://git-scm.com/docs/git-add
  5. https://devconnected.com/how-to-cherry-pick-git-commits/
  6. https://phoenixnap.com/kb/git-revert-last-commit
  7. https://stackoverflow.com/questions/41842149/error-commit-is-a-merge-but-no-m-option-was-given
  8. https://superuser.com/questions/1309196/how-to-update-authentication-token-for-a-git-remote
  9. https://www.git-tower.com/learn/git/faq/cherry-pick/
  10. https://stackoverflow.com/questions/17683458/how-do-i-commit-case-sensitive-only-filename-changes-in-git
  11. https://github.com/delventhalz/no-fear-git

Last modified: 202110141548

Rebase (git)

Rebasing in git is a way to clean up your commit history and change the history of one branch to be after the changes of another. Most commonly, you rebase a feature branch on the end of the master/main branch.

Merge vs. Rebase

Merging and rebasing both achieve the same goals, but in different ways. Merging non-destructively maintains the history of the current branch when merging in other branches, with the cost of adding a new merge commit. Rebasing destructively changes the history of the current branch when rebasing on to other branches, but leaves no new commits.

Golden Rule

If your branch is being worked on by anybody else but you, do not rebase! Because rebase is destructive, you will not be able to reconcile branches with git, leaving you to do the work manually. 💀⚰️

Simple Rebase

To perform a simple rebase and put the commits of the current branch on to the tip of another branch, you can use the following command:

$ git rebase {other-branch}

For instance, if I were on a feature branch and I wanted to rebase on top of the main branch, I would use git rebase main. This will re-write the history destructively and prompt you if there are any conflicts to resolve before proceeding.

Interactive Rebase

To rebase one branch onto the nearest common ancestor of another, use the following command:

$ git rebase -i `git merge-base {other-branch} HEAD`

For instance, if I was on a feature branch and wanted to interactively rebase over all commits that occurred since it branched off of main, it would be git rebase -i `git merge-base main HEAD` .

Note that when the commits are listed, they are listed oldest to newest, unlike the git log which is newest to oldest. This is very important!

Interactive Rebase Commands

I only have used these so far, and they do the job for what I need.

Command(s) Effect
p / pick Keep the commit as it currently is
r / reword Keep the commit and edit the commit message
s / squash Combine this commit with the previous commit, and edit commit message for newly squashed commit
f / fixup Fold this commit into the previous commit, using the previous commit's message

References

Last modified: 202110211444

Salary Negotiation

Like the article I am summarizing from, I hate this. I'm hoping that through using this information, I can better advocate for myself and be a greater force for the values and principles I believe in.

  1. Don't give hard numbers to recruiters; ask for a range that you can discuss later
  2. Ask questions of the employer during the interview to use in negotiations
    • What’s the biggest priority for the team right now?
    • Why is this role open?
    • What’s the biggest challenge for someone stepping into this role?
    • How does the org structure on the team work?
  3. When offered a job, still don't give hard numbers; recruiters are still working for the company after all
  4. At FAANG companies, salary is often decided by a team; giving a number can only hurt later negotiations (if you do end up giving a number, renogiations will be necessary when counteroffers are given from other companies or your current one). Evaluate what your initial offer from the company means using the band you asked for at step 1:
    • Below: Ask for feedback on why they perceive you to be at the bottom of the band and fix any misconceptions before negotiating. You need a solid place to argue from
    • Middle: You may not have a strong advocate in the company. Match with a team or manager who is willing to do so before negotiating.
    • Above: There may have been a discussion of putting you at a higher level. Can possibly push out of the aforementioned band.
  5. At startups, it's more of a wild west scenario; figure out the current state of the company in terms of finances, wher you will be at the company and what you'll be doing, and the value of the equity they will offer you. You are going to be an investor in the startup, so treat it like you would any investment: be skeptical, ask a LOT of questions, vet thoroughly, do tons of research.
  6. Win the support of your future teammates and current decision-makers; understanding what they want and need from who fills the role and how you can help them achieve it will make it more likely for them to vouch for you and the higher wage.
  7. Compare the data you have gotten with existing data: does it make sense? Compare
    • Wages
    • Value of the equity
    • Stocks
  8. Compare this offer with all others you have received. Determine which has the qualities you most desire in a company:
    • Long term trajectory
    • Company culture
    • Promotion structure
    • Manager's ability to vouch for you
    • Brand worth for your long term trajectory
  9. Make the ask. WIth the data you have considered and what you need, make the ask that is best for you, justified by the data.

References

Last modified: 202109250003

Forming, Storming, Norming, and Performing

This is a framework of how a team moves from no experience or knowledge of each other to established. This was first proposed by Bruce Tuckman in 1965.

The Framework

I'll use some text from the sites in the references below as prompts for my own reflection, here.

Forming

In the beginning, when a new team forms, individuals will be unsure of the team's purpose, how they fit in, and whether they'll work well with one another. They may be anxious, curious, or excited to get going. However they feel, they'll be looking to the team leader for direction.

In polling my past experiences, the times I was leading with excitement in getting to know others or learn something was when this worked out best, as opposed to trying to put my best foot forward and paint a "good first impression" of who I want people to think I am.

Storming

In the storming stage, people start to push against the established boundaries. Conflict or friction can also arise between team members as their true characters – and their preferred ways of working – surface and clash with other people's.

I tend to do a lot of "stumbling around in the dark" here. Doing stuff sort of indiscriminately, banging into walls, discovering the boundaries, asking lots of questions, and gauging what the goals are of the team and of the people within it. Depending on the project, I get excited by the possibilities of the work that might occur, the end results, the fun I can have while doing it, etc. If I feel secure in the team, I will make a LOT of mistakes, sometimes on purpose, to find out what the edges are and what the real rules and values of the team are.

If roles and responsibilities aren't yet clear, individuals might begin to feel overwhelmed by their workload or frustrated at a lack of progress.

(Emphasis mine)

In this stage, if I find that there is a disconnect between the roles put forward and what is actually done, or the values presented and the actions performed, or the authority figure's words and actions, I tend to bring those things up. I believe this is the first instance where I can tell whether or not a job will work out for me, as I have a lot of difficulty in being expected to do something that doesn't make sense in the holistic sense of the company.

When I bring up these observations, the way they are responded to usually points towards whether things are going to work out in the long term. In my relationship with parents, teachers, teaching assistants, bosses, supervisors, etc., I have found that if I don't feel that I can have open and honest communication, I will feel frustrated and fearful of what this may mean months in the future. It brings up feelings of being gaslit, and a value of product over process at all costs. I believe that mindset leads to penny-wise and pound-foolish behavior, which often trickles down into treatment of the employees.

Norming

This and performing tend to fall into the same mental space for me, so there is probably overlap.

Gradually, the team moves into the norming stage. People start to resolve their differences, appreciate one another's strengths, and respect [the] authority as a leader.

Once through the storming phase, this stage seems like it has gone two distinct paths in the past with me. Either I feel secure and supported by my team, and aligned with the values they are presenting through their actions, or I feel unsupported and frustrated by my team or not aligned.

The former is where I feel I can do my best. If I can get through that phase and feel like this is a place where I (as a human being, but also as a worker) can thrive, be valued, and be treated with sovereignty, I will be prepared to give what I believe to be my best effort.

The latter, however, is a different situation. Wikipedia sums it up well:

The danger here is that members may be so focused on preventing conflict that they are reluctant to share controversial ideas.

Feeling insecure or unvalued as a sovereign person in these situations leaves me to emotionally "curl up and hide in the corner". Deep down, I believe my psyche notes what is safe and unsafe to do, and overturning that "list" feels near impossible once established.

Performing

Again, in the former:

Now your team is in flow and performing to its full potential. With hard work and structured processes, the team is likely to achieve its goals efficiently.

The team members are now competent, autonomous and able to handle the decision-making process without supervision. Dissent is expected and allowed as long as it is channelled through means acceptable to the team.

But in the latter, it will feel like hoop-jumping or clock-watching, waiting for the end of each day with dread. I will vouch for myself, my team, and my work out of frustration rather than joy, and will only speak up if necessary, despite that I may have many ideas or opinions that I believe could help the team.

References

Last modified: 202110241917

Consulting

Can I give you consulting math 101? You may already know this, and if so, forgive me.

  • Decide how much you want to make. Let's use a nice round number. USD$100,000 (Not saying this is your number, yours may be USD$250,000, or whatever. This is just an example.)
  • Remember to add health insurance, business insurance, error & omission insurance, taxes and fees and everything else. (Call an insurance broker, techinsurance.com, etc.)
  • Let's call this compiled number USD$150,000. (again, just an example.)
  • Double it. USD$300,000. You can expect no more than 50% utilization, and you have to spend time finding the next client/gig/opportunity. So you will only make half a years worth of hourly salary.
  • Convert to hourly. There are 2080 working hours in a year. So you can have a vacation, call it 2000. Divide 300,000 by 2,000. That's 150. So your hourly rate is $150/hour.
  • If you are 50% utilized, you will make USD$150,000 per year. With six months of time to find work, have a vacation, keep your certs alive, and expand your skill set.

References

Last modified: 202109190517

Foraging

DO NOT EAT WHAT YOU CANNOT IDENTIFY 100%! If you can't for SURE identify what the plant or food is without any ambiguity, it CAN KILL YOU. See Atomic Shrimp's video on beginning foraging to understand the risks. This is not a harmless activity, it can be life or death.

Peruvian Peppercorn

In America, this tree can be found in Southern California, Hawaii, and Florida.

Identification

Schinus molle is a quick growing evergreen tree that grows up to 15 meters (50 feet) tall and wide. It is the largest of all Schinus species and potentially the longest lived. The upper branches of the tree tend to droop. The tree's pinnately compound leaves measure 8–25 cm long × 4–9 cm wide and are made up of 19-41 alternate leaflets. Male and female flowers occur on separate plants (dioecious). Flowers are small, white and borne profusely in panicles at the ends of the drooping branches. The fruit are 5–7 mm diameter round drupes with woody seeds that turn from green to red, pink or purplish, carried in dense clusters of hundreds of berries that can be present year round. The rough grayish bark is twisted and drips sap. The bark, leaves and berries are aromatic when crushed.

See the Wikipedia page for pictures of the distinctive bark and berries.

Food

The ripened peppercorns can be used as a fruity spicy addition to dishes, particulary for seafood, salads, curries, cheese, chocolate, or popcorn. "spicy and peppery, but have a very fragrant, sweet-tart and rosy tone."

Preparation

  • Pick the berries from the branches once they are ripe and bright pink, trying to remove as much branch as possible, but it's not a biggie if some are left.
  • Set them on a single layer sheet or plate and let them dry out over a few days. This should result a dried fruit outer layer around the seed inside.
  • Store these dried peppercorns away from direct sunlight and heat to maintain freshness.

Use

Use these dried peppercorns with mortar and pestle or crushed with the flat side of a knife to release their oils. They can also be roasted prior to use to release more aromatics. They can also be mixed with regular peppercorns, but can easily be overwhelmed, and the thin skin can clog the pepper grinder. Interestingly, they can also be used whole, as they are milder than other types of peppercorns.

The potency will start to decline six months or so after preparation.

References:

References

Last modified: 202110162222

Rubik's Cube

The Rubik's Cube is a puzzle that is solved by utilizing algorithms.

Glossary

Notation Description
F (Front) the side currently facing the solver
B (Back) the side opposite the front
U (Up) the side above or on top of the front side
D (Down) the side opposite the top, underneath the Cube
L (Left) the side directly to the left of the front
R (Right) the side directly to the right of the front
f (Front two layers) the side facing the solver and the corresponding middle layer
b (Back two layers) the side opposite the front and the corresponding middle layer
u (Up two layers) the top side and the corresponding middle layer
d (Down two layers) the bottom layer and the corresponding middle layer
l (Left two layers) the side to the left of the front and the corresponding middle layer
r (Right two layers) the side to the right of the front and the corresponding middle layer
x (rotate) rotate the entire Cube on R
y (rotate) rotate the entire Cube on U
z (rotate) rotate the entire Cube on F

Directions

Last modified: 202110221727