I passed the exam last week with a score of 853. So these are the resources that I used.
I used most of my 10 weeks - 7 or 8 of them - to go over the Cantril course. On average, I would say I spent 1-2 hours every day, including weekends (more on the final days leading to the exam). We get a learning day at work once every two weeks, and I would spend 5-6 hours on those days.
Anyway, I followed the Cantril course with the Maarek course. From day 1, I also spent around 15-20 minutes a day going over pre-made flashcard decks. Once I finished the Cantril course, I started going over the exams and putting all the exam questions in my own Anki deck. I did Brainscape flashcards - they're pretty - when I got bored. Lots of mock exams and reviewing in the final days leading up to the exam. That's it!
No, I don't think so. Do more labs and practical work (the Cantril labs are excellent with very clear walk throughs), and make sure that the knowledge sticks more, but the rest was great. Booking the exam early on puts that extra bit of motivation to get things done.
]]>There are two options - that I know of -, git checkout
and git restore
.
Both git checkout <commit> <filename>
and git restore --source <commit> <filename>
allow you to restore a specific file to the state it was in at a particular commit.
But there are some differences in how they work.
The git checkout <commit> <filename>
command updates the file in your working directory and in the index to match the specified commit. It effectively changes the HEAD
pointer to the specified commit, then updates the file to its state at that commit.
This can cause potential problems if you have changes in your working directory that conflict with the changes you are trying to restore. In such a case, Git will show you an error and ask you to commit or stash your changes before proceeding.
git restore --source <commit> <filename>
command restores the file in your working directory to the specified commit, but WITHOUT updating the index or changing the current branch.
Most commonly, this is used to undo changes you made to a file in your working directory while leaving the other changes intact.
Meaning git checkout <commit> <filename>
changes the HEAD pointer AND updates the file in the index, while git restore --source <commit> <filename>
ONLY restores the file in the working directory and does not change the HEAD pointer or the index.
So, if you want to restore a file to a previous state without affecting other changes in your repository, git restore
is typically a safer command
2022 was a year of moving. We started the year in Brussels but preparing to move back to the UK. Because we knew neither of us would have to work in the office, we decided, why not, let's live somewhere picturesque. Mid-January, I flew to Manchester to find us a house to rent in the Lake District for the next nine months, cause you know, ideas!
Optimistically, I thought it could all be done in a week - it took me four weeks instead! Luckily I'm a pragmatic packer.
I spent the extra weeks working from an Airbnb in Manchester, buying us a used car (Mindy!) and some basic furniture (the house we were renting came unfurnished, and our stuff was 🐌 somewhere between Brussels and the UK). Then off to Milton Keynes with a train, sleep, rent a car with Neil, drive to Brussels, the band re-united, wife, dog, cat, cat, all there, sleep and head back to the Lake District, boom!
Then the lovely lake district until October with lots of walks and swimming in lakes and us living from boxes and makeshift furniture - knowing we'll move soon, we wanted to keep most of our stuff packed and buy only a little furniture. #glamping
Valerie did her language immersion in September in Greece, so we spent almost five weeks apart. Did not particularly enjoy that, no.
But, on the plus side, Valerie and I have been together for more than 11 years now and are still very much in love!
Then another road trip to Athens, this time to it took us six days - oh, but it was gorgeous - including a 23-hour ferry from Italy (yes, the pets were there with us in the tiny cabin) and then finally Athens, where we're now and will be for the next four or five years. (And no, we're still not fully unpacked...)
I switched jobs! VIBBIO, was my first full-time job as a software developer, but after three years, I wanted to try something else. The job-hunting process was (surprisingly!) smooth (it took me around three weeks from start to finish), and I've just passed my six-month mark at Lottie.
Yet another year of Zoom: the weekly family hangouts, chatting with my sister, the movie club, the study groups, and playing board games online.
Friends came to visit us in Lake District, too; lots of walks and exploring, kayaking, and trying not to be offended by all the rain and wind.
Following the Got7 concert in the O2, we both got covid. I got hit quite hard, was really poorly for two days, and was super weak for another 2-3 weeks. Stairs remained a challenge for quite some time.
Our precious Gytha 🐕 got an eye - we thought tumor, for sure, and imagined the worst scenarios, it turns out (for now!) it's benign, and we just have to keep an eye on it. 🥁
I've mostly stopped eating dairy products: no eggs or milk. The only issue since moving to Greece is feta cheese, which is everywhere. But in any case, when at home, we eat vegan + some fish.
I've been good with exercise: lots of running, some bodyweight training (I will learn how to do those handstands, damnit!), and recently some weight lifting.
I use Anki every day, first thing in the morning, for 45-60 min. I use it for Greek, Chinese, Spanish, programming, keyboard shortcuts, general knowledge, and anything I want to remember.
I don't know when I started, but 2022 was the year I started using Obsidian for all my note-taking and note reviewing. I love it. I keep experimenting with how I use it (daily notes or not, data views, tagging, links, styling, themes), but the core features - markdown files and easy file creation and linking - remain unbeatable. Unfortunately, this is also the main reason why I hardly write any blog posts these days.
I've been learning Greek for over a year now and consider myself at an intermediate level. Most of it has been self-study, plus I've had two hours of 1:1 classes since June.
For most of the year, I've also had weekly 1:1 Mandarin Chinese classes just to maintain my level. I've stopped when things have gotten too busy with the move to Greece and haven't restarted yet. I don't think I have the brain power at the moment.
Because of Lottie, I've had to pick up NextJS and Tailwind. I've also spent a lot of time improving my TypeScript skills.
- Learning (programming): Docker, AWS, Racket, maybe learn Vim? 🤷♀️ Get really good at TypeScript. - Learning (languages): Get Greek to an advanced level - Mentoring and organizing: get back to mentoring and organizing study groups once I've recovered from the move.
You will need to learn the alphabet before doing anything else 😅.
These YT videos:
Grammar
Note: I recommend buying Greek keyboard stickers, which you can tape over your computer/laptop's keyboard
I'm particularly interested in working with refugees and minorities in tech. I've done a lot of teaching/volunteering in the past, specifically Django Girls workshops, Cryptoparties, Nodeschools, and lots of Free Code Camp meetups.
And as a side note, my first impression of Athens is: really good! Of course, Athens is way busier than our sleepy life in the Lake District, but in the few days we'd been here, we found the people friendly, the food delicious, the coffee soothingly made the same way we do it in Slovenia, and the weather a nice change.
Gytha 🐕 is a star; everyone loves her and wants to pet her! The cats are happy with the abundant opportunities to sunbathe.
I'm not particularly looking forward to driving anytime soon, but luckily we're based quite in the center (Pangrati), so everything is within walking distance - if you like walking for a while 😅. But damn, the Athens streets are hilly!
]]>I feel that currently, my biggest issue with debugging is scoping. While working on a specific bug, I sometimes find other (unrelated!) issues, and so I also fix those - since I'm in the area, you know! This results in a muddier chunk of work submitted, not to mention that I sometimes introduce new bugs 🤦♀️.
Below are my notes from chapter 23:
I spend around 30 minutes reading the newsletters (about two or three every day). Then, depending on the newsletter type, I either add some notes in Obsidian, add some flashcards to Anki, bookmark the articles, forward relevant bits to my friends or hit unsubscribe. 🔪
My bookmarks live inside my 'Reading' folder inside the Firefox browser. I again try to process two or three items each day (currently, that folder has 28 links! 😱).
If possible, I read everything with Firefox's reader view (not all websites allow it) - it has a nice big font and fewer distractions.
I try to be ruthless when it comes to unsubscribing or deleting bookmarks - if something has lingered in my inbox for more than a month, that clearly means I'm not interested, so bin it is. Life's too short, and there's an unending flow of interesting/useful information. 💡
I also try no to stress about it, and if at some point I accumulate too many of these unprocessed items, I just do a mass delete and start all over.
I've been thinking about this a lot.
Here's what the book says about conquering complexity, along with the rest of my notes from one of my favorite chapters: Chapter 34 Themes in software craftsmanship.
Summary of the principles covered in the course:
When length of password is 4:
Iterating through all possible passcodes with python:
from string import ascii_letters, digits, punctuation
from itertools import product
for passcode in product(ascii_letters + digits + punctuation, repeat=4):
print("".join(passcode))
If you use an 8-character password instead, it's six quadrillions (six followed by fifteen zeroes) 💡
Pseudocode:
if player is X:
for all possible moves:
calculate score for board
choose move with highest score
else:
for all possible moves:
calculate score for board
choose move with lowest score
there are 255,000 thousand possible games of tic-tac-toe
for chess, only considering the first four moves, there are 288 billion possible games
depth-limited minimax: uses an evaluation function which is used to estimate the expected utility of the game from a given state (limiting the path of branches we follow)
E.g., epsilon greedy approach:
epsilon = 0.10
if random() < epsilon:
make a random move
else:
make the move with the highest value
make initial generation of candidates randomly
repeat until successful:
for each candidate:
calculate candidate's fitness
remove least fit candidates
make new generation from remaining candidates
raw
and endraw
to prevent 11ty from crashing the site)Typical project structure in flask:
application.py
requirements.txt
static/
templates/
appplication.py
)# in application.py
# render_template is similar to open(), read()
# reuest is for reading params
from flask import Flask, render_template, request
# refers to the name of the current file
# Flask, turn the current file into a flask app
app = Flask(__name__)
# python decorator @ is a special way of
# applying one function to another
@app.route("/")
def index():
# needs templates/index.html file
# you can plug the into the template
# ?name=Eva to use, but with "world" for default
return render_template("index.html", name=request.args.get("name", "world"))
flask run
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>hello</title>
</head>
<body>
<form action="/greet" method="post">
<input name="name" type="text">
<input type="submit">
</form>
</body>
</html>
Back in the controller:
@app.route("/")
def index():
return render_template("index.html")
# get is the default, other methods you have to pass
# request.args.get for GET and request.form.get for POST
@app.route("/greet", methods=["POST"])
def greet():
return render_template("greet.html", name=request.form.get("name", "world"))
jinja
templating language:<!DOCTYPE html>
<html lang="en">
<head>
<title>hello</title>
</head>
<body>
</body>
</html>
Which is used like this:
{% extends "layout.html" %}
{% block body %}
hello, {{ name }}
{% endblock %}
We can reuse the same route, of course:
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
return render_template("greet.html", name=request.form.get("name", "world"))
return render_template("index.html")
Inside application.py
:
from flask import Flask, render_template, request
app = Flask(__name__)
SPORTS = [
"Dodgeball",
"Flag Football",
"Soccer",
"Volleyball",
"Ultimate Frisbee"
]
@app.route("/")
def index():
# passing the sports var to the index template
return render_template("index.html", sports=SPORTS)
@app.route("/register", methods=["POST"])
@app.route("/register", methods=["POST"])
def register():
# basic error handling
if not request.form.get("name") or request.form.get("sport") not in SPORTS:
return render_template("failure.html")
return render_template("success.html")
return render_template("success.html")
from cs50 import SQL
from flask import Flask, redirect, render_template, request
app = Flask(__name__)
# make sure to create a db
db = SQL("sqlite:///froshims.db")
@app.route("/register", methods=["POST"])
def register():
# better error handling with custom message
name = request.form.get("name")
if not name:
return render_template("error.html", message="Missing name")
sport = request.form.get("sport")
if not sport:
return render_template("error.html", message="Missing sport")
if sport not in SPORTS:
return render_template("error.html", message="Invalid sport")
db.execute("INSERT INTO registrants (name, sport) VALUES(?, ?)", name, sport)
# redirecting to registered users page
return redirect("/registrants")
@app.route("/registrants")
def registrants():
registrants = db.execute("SELECT * FROM registrants")
return render_template("registrants.html", registrants=registrants)
And inside registrants.html
<tbody>
{% for registrant in registrants %}
<tr>
<td>{{ registrant.name }}</td>
<td>{{ registrant.sport }}</td>
<td>
<form action="/deregister" method="post">
<input name="id" type="hidden" value="{{ registrant.id }}">
<input type="submit" value="Deregister">
</form>
</td>
</tr>
{% endfor %}
</tbody>
import os
import re
from flask import Flask, render_template, request
from flask_mail import Mail, Message
app = Flask(__name__)
app.config["MAIL_DEFAULT_SENDER"] = os.getenv("MAIL_DEFAULT_SENDER")
app.config["MAIL_PASSWORD"] = os.getenv("MAIL_PASSWORD")
app.config["MAIL_PORT"] = 587
app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_USE_TLS"] = True
app.config["MAIL_USERNAME"] = os.getenv("MAIL_USERNAME")
mail = Mail(app)
@app.route("/register", methods=["POST"])
def register():
# we changed the name to email
email = request.form.get("email")
if not email:
return render_template("error.html", message="Missing email")
sport = request.form.get("sport")
if not sport:
return render_template("error.html", message="Missing sport")
if sport not in SPORTS:
return render_template("error.html", message="Invalid sport")
message = Message("You are registered!", recipients=[email])
mail.send(message)
return render_template("success.html")
from flask import Flask, redirect, render_template, request, session
from flask_session import Session
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
@app.route("/")
def index():
# if not logged in, redirect to login
if not session.get("name"):
return redirect("/login")
return render_template("index.html")
# remember to support both methods
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
# saving the name inside the globally
# available session const
session["name"] = request.form.get("name")
return redirect("/")
return render_template("login.html")
@app.route("/logout")
def logout():
# deleting the 🍪
session["name"] = None
return redirect("/")
And index.html
:
{% extends "layout.html" %}
{% block body %}
{% if session.name %}
You are logged in as {{ session.name }}. <a href="/logout">Log out</a>.
{% else %}
You are not logged in. <a href="/login">Log in</a>.
{% endif %}
{% endblock %}
@app.route("/search")
def search():
shows = db.execute("SELECT * FROM shows WHERE title LIKE ?", "%" + request.args.get("q") + "%")
# make sure to import the jsonify library from flask
# this will convert a python dict into a json object
return jsonify(shows)
And finally this is how you'd dynamically display the search results (using jQuery 😱):
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="initial-scale=1, width=device-width">
<title>shows</title>
</head>
<body>
<input autocomplete="off" autofocus placeholder="Query" type="search">
<ul></ul>
<script crossorigin="anonymous" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
let input = document.querySelector('input');
input.addEventListener('keyup', function() {
$.get('/search?q=' + input.value, function(shows) {
let html = '';
for (let id in shows)
{
let title = shows[id].title;
html += '<li>' + title + '</li>';
}
document.querySelector('ul').innerHTML = html;
});
});
</script>
</body>
</html>
]]>HTTP
, 442 for HTTPS
)GET
allows a browser to ask for a page or file, and POST
allows a browser to send data to the serverhttps
with encrypted content of the packets) + domain name (google.com
) + hostname (www
aka world wide web and not a mail or chat server) + /
requesting the default file (index.html
).com
is known as TLD or top-level domainhttp-server
Instead of event.preventDefault()
return false
🤔
<body>
<form onsubmit="greet(); return false;">
<input id="name" type="text">
<input type="submit">
</form>
</body>
Wait for the dom to be loaded before proceeding with JS (instead of moving the <script>
tag all the way down).
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('form').addEventListener('submit', function() {
let name = document.querySelector('#name').value;
alert('hello, ' + name);
});
});
lambda
.csv
is a flat-tile databasewith open
for opening files, it will handle the eventual closing of the file as well. So essentially, the file will remain open while you are indented inside the with
block.DictReader
presumes that the first row is going to be column headings (if your file doesn't have headers, you'll have to manually configure DictReader
)# printing only unique values
import csv
# a colection of unique values
titles = set()
with open("Favorite TV Shows - Form Responses 1.csv", "r") as file:
reader = csv.DictReader(file)
for row in reader:
# the dict reader is aware of the column names
# trim and uppercase the entries
titles.add(row["title"].strip().upper())
# let's sort as well
for title in sorted(titles):
print(title)
This is how you'd define a dictionary:
titles = dict()
#or
titles = {}
# dict vote counter
for row in reader:
title = row["title"].strip().upper()
if title not in titles:
titles[title] = 0
titles[title] += 1
And this is how you'd sort by dict value (not key):
def f(title):
return titles[title]
# 🤯 you can pass in functions to sorted
for title in sorted(titles, key=f, reverse=True):
# for short (anonymous) functions, you can write them inline like this:
# lambda arguments: return value
for title in sorted(titles, key=lambda title: titles[title], reverse=True):
.csv
, the data is now stored in a binary filesqlite3
command-line tool for interacting with the db.csv
file into sqilite3
When working with data, you generally deal with these four actions:
CREATE
and INSERT
SELECT
(aka READ
in the CRUD
world)UPDATE
DELETE
Examples:
SELECT title FROM shows;
SELECT * FROM shows;
(selects all columns)SQL supports many functions that we can use to count and summarize data:
AVG
COUNT
DISTINCT
, for getting distinct values without duplicatesLOWER
MAX
MIN
UPPER
You can also add clauses, or phrases that modify the query:
WHERE
, matching results on a strict conditionLIKE
, matching results on a less strict conditionORDER BY
, ordering results in some wayLIMIT
, limiting the number of resultsGROUP BY
, grouping results in some wayExample queries:
sqlite> SELECT title FROM shows WHERE title LIKE "%Office%";
sqlite> SELECT DISTINCT(UPPER(title)) FROM shows ORDER BY UPPER(title);
SELECT UPPER(title), COUNT(title) FROM shows GROUP BY UPPER(title) ORDER BY COUNT(title);
🤔 What does it mean to normalize data?
BLOB
, for “binary large object”, raw binary data that might represent filesINTEGER
NUMERIC
, number-like but not quite a number, like a date or timeREAL
, for floating-point valuesTEXT
, like stringsNOT NULL
, there must be some valueUNIQUE
, means that the value for that column must be unique for every row in the tablePRIMARY KEY
, like the id
column above that will be used to uniquely identify each rowFOREIGN KEY
, like the show_id
column above that refers to a column in some other tableBack in our Python file, this is how you can create a squlite db programmatically:
from cs50 import SQL
open("shows.db", "w").close()
db = SQL("sqlite:///shows.db")
db.execute("CREATE TABLE shows (id INTEGER, title TEXT, PRIMARY KEY(id))")
db.execute("CREATE TABLE genres (show_id INTEGER, genre TEXT, FOREIGN KEY(show_id) REFERENCES shows(id))")
with open("Favorite TV Shows - Form Responses 1.csv", "r") as file:
reader = csv.DictReader(file)
for row in reader:
title = row["title"].strip().upper()
# saving the id to use it as FOREIGN KEY in a bit
# using the ? as a placeholder
id = db.execute("INSERT INTO shows (title) VALUES(?)", title)
for genre in row["genres"].split(", "):
db.execute("INSERT INTO genres (show_id, genre) VALUES(?, ?)", id, genre)
More queries:
SELECT title FROM shows WHERE id IN (SELECT show_id FROM genres WHERE genre = "Musical");
INTEGER
smallint
, with fewer bitsinteger
bigint
, with more bitsNUMERIC
boolean
date
datetime
numeric(scale,precision)
, with a fixed number of digitstime
timestamp
REAL
real
double precision
, with twice as many bitsTEXT
char(n)
, a fixed number of charactersvarchar(n)
, a variable number of characters, up to some limit n
text
, a string with no limitO(n)
): sqlite> CREATE INDEX title_index ON shows (title);
B-trees
, like binary trees in C, with nodes organized such that we can search faster than linearlyB-tree
is a family tree that is very wide and not that tall (aka it tries to keep the leaf nodes as close to the root as possible)SELECT title FROM people
JOIN stars ON people.id = stars.person_id
JOIN shows ON stars.show_id = shows.id
WHERE name = "Steve Carell";
TRANSACTIONS
which lock a specific row in a table to only one update at a time.print("hello, world")
var
or similar keyword.py
python program.py
from CS50 import get_string
main
function!or
instead of ||
# this is a comment
elif
(instead of else if
)not
instead of !=
letter_only = True if input().isalpha() else False
🤯do while
loopsi++
or i--
print()
adds a new line by default (so you don't need to add \n
yourself)append()
vs push()
for lists (they're not arrays)None
instead of NULL
from cs50 import get_string
answer = get_string("What's your name? ")
# no need to deal with separate placeholders
print("hello, " + answer)
# OR
print(f"hello, {answer}"
# you can use formatted string with any string function not just printf 💡
counter++
doesn't exist in Python (counter += 1
)# no curly braces, no semi-colons, no extra lines
# but yes, indentation!
# pay attention, : instead of {
if x < y:
print("x is less than y")
# instead of else if
elif x > y:
print("x is greater than y")
else:
print("x is equal to y")
# capitalizing the booleans
while True:
print("hello, world")
i = 0
while i < 3:
print("hello, world")
i += 1
for i in [0, 1, 2]:
print("cough")
# or
for i in range(3):
bool
, float
, int
, str
but alsorange
, list
(an array that automatically re-sizes itself), tuple
, dict
, set
(a collection of values without duplicates)double
or long
words = set()
# this is how you define a function in python
def load(dictionary):
file = open(dictionary, "r")
for line in file:
words.add(line.rstrip())
file.close()
return True
def check(word):
if word.lower() in words:
return True
else:
return False
def size():
return len(words)
def unload():
return True
🤔 Why is Python slower than C?
answer = input("What's your name? ")
print(f"hello, {answer}")
# this is pretty neat
if s.lower() in ["y", "yes"]:
# you still need to define something before calling it
def main():
meow(3)
def meow(n):
for i in range(n):
print("meow")
main()
for c in s:
# the second argument overrides the default \n
print(c.upper(), end="")
from sys import argv
if len(argv) == 2:
print(f"hello, {argv[1]}")
else:
print("hello, world")
# importing the entire library here
import sys
if len(sys.argv) != 2:
print("missing command-line argument")
sys.exit(1)
print(f"hello, {sys.argv[1]}")
sys.exit(0)
nums = [1, 2, 3, 4]
# insert 5 at position 4
nums.insert(4, 5)
from cs50 import get_string
people = {
"Brian": "+1-617-495-1000",
"David": "+1-949-468-2750"
}
name = get_string("Name: ")
if name in people:
print(f"Number: {people[name]}")
🤔 How do you run python locally?
cd
mkdir pyworkshop
cd pyworkshop
python3.7 -m venv env
source env/bin/activate
# and to kill it write deactivate
Some more nifty Python functions
type
for checking out the type of the variabledir
for listing all the methods on the data typehelp
Data structures are more complex ways to organize data in memory, storing information in different layouts. We'll look at:
🤔 Garbage values aren't bad - you just don't know what they are.
Summary
NULL
pointer).
for accessing a struct property and the *
(go to the address of) operator are shorthanded into ->
n->next = NULL;
//instead of
(*n).next = 1;
// because this is a self-referential data type
// we need to give it a temp name to use it immediately
// and then return the name we actually want to call it
typedef struct tempNode
{
int number;
struct tempNode *next;
}
node;
Your newly initialized variable will contain garbage values unless if you set it to NULL
.
How do you create a linked list?
// an empty linked list
node *list = NULL
// We use sizeof(node) to get the right amount of memory to
// allocate, and malloc returns a pointer that we save as n
node *n = malloc(sizeof(node))
// We want to make sure malloc succeeded in getting memory for us
if (n != NULL)
{
// This is equivalent to (*n).number, where we first go to the
// node pointed to by n, and then set the number property.
// In C, we can also use this arrow notation
n->number = 1;
// Then we need to make sure the pointer to the next node in our // list isn't a garbage value, but the new node won't point to
// anything (for now)
n->next = NULL;
}
But steps involved are:
❗Always insert to the beginning of the list - you already have the pointer to the list's HEAD
One of the trickiest things with linked lists is figuring out the order of doing this - you certainly don't want to end up with an orphaned list! When inserting items, always make sure to point to the next item (i.e., previous head) first, before changing the HEAD
of the list.
🤔 Every time you allocate memory with malloc, you need to check whether that value != NULL before doing stuff to it. Every time you stuff with pointers, you need to check for NULL
as well
Tradeoff: we need to allocate twice as much memory for each element in order to spend less time adding values. We can't use binary search.
Summary
Trees are recursive data structures where each node points to two other nodes, one to the left (with a smaller value) and one to the right (with a larger value). Meaning each node has at most two children, or nodes it is pointing to.
typedef struct node
{
int number;
struct node *left;
struct node *right;
}
node;
Tradeoff: incurred even a larger memory cost - since each node now needs space for a value and two pointers. It can be used as a binary search tree (as long as the data is sorted, of course).
Summary
Summary
int
s are four byes.0x
hex
color values are just the hexadecimal RGB values (and in a different format)!&
"the address of" operator (we use it every time we want to check what address a variable is stored at)*
"go to the address of" operator(for telling your program to look inside a particular memory address). Also known as the dereferencing operator.%p
- aka pointer - for the placeholder value to be interpreted as hexadecimalint n = 50;
prinf("%p\n", &n)
// returns eg: 0x123456789
// this will just print out 50
prinf("%i\n", *&n)
And if you want to store the address of some variable inside another variable, you would use a pointer (an int star
variable):
int n = 50;
int *p = &n;
// and to print the value stored at p
// get the value at the address
prinf("%i\n", *p)
long
)A string is defined as back-to-back-to-back characters (one byte away, since a char
take one byte of space in C).
int n = 50;
int *p = &n;
string s = "EMMA";
char *s = "EMMA";
typedef char *string;
🔈 NEW STRING DEFINITION: A string is a variable that contains the address of a character, aka char *
char *s = "EMMA";
printf("%p\n", s); // the address of the char
printf("%p\n, &s[0]); // the address of the 1st char (same as ^)
printf("%c\n", *s); // prints "E"
// pointer arithmetic
printf("%c\n", *(s+1)); // prints "M"
s == t
you are comparing their addresses in the memory, meaning these two strings will never be the same! (that's why you need to use strcmp()
instead)// changing one, will change the other
char *s = get_string("s: ");
char *t = s;
t[0] = toupper(t[0]);
// copying a string in c
// without using strcopy()
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *s = get_string("s: ");
char *t = malloc(strlen(s) + 1);
// when allocating memory always check that malloc
// is giving you back a valid memory address and not NULL
if (t == NULL)
{
return 1;
}
// we need to include \0 that's why n + 1
// or i <= n
for (int i = 0, n = strlen(s); i < n + 1; i++)
{
t[i] = s[i];
}
if (strlen(t) > 0)
{
t[0] = toupper(t[0]);
}
printf("s: %s\n", s);
printf("t: %s\n", t);
free(t);
}
malloc()
- memory allocate
free()
- freeing the memory previously allocated
strcpy(str1, str2)
- for copying strings
**Anytime you use malloc()
, you must use free()
afterward.
valgrind
debugging tool helps you debug invalid reads, invalid writes, segmentation faults, or memory leaks (aka when you've allocated more memory than you have freed)valgrind ./hi
cs50
to get a more helpful output.🤔 What is a garbage value?
int *x = malloc(10 * sizeof(int));
// allocate enough memory for 10 integers, and then
// store the address of that chunk of memory
// in a pointer called x.
🤔 What is a buffer overflow?
When you are overflowing the allocated memory (either stack overflow or heap overflow)
In terms of standard order (you can imagine it going top to bottom):
// swapping values in C
// note you must use pointers!
// otherwise only params a, b will be changed
// but the original x, y will remain as they were
// you wouldn't need pointers if you did all
// the swapping inside main
#include <stdio.h>
void swap(int *a, int *b);
int main(void)
{
int x = 1;
int y = 2;
printf("x is %i, y is %i\n", x, y);
swap(&x, &y);
printf("x is %i, y is %i\n", x, y);
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
// vs naive, old version of swap
// that doesn't change x, y
void swap(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
Meaning! If you use the stack's memory you save yourself the trouble of having to do malloc()
AND free()
🤯
char s[4];
// vs
char *s = malloc(4);
All the CS50 get
libraries (get_int
, get_string
), were there to help you with pointers.
Equivalent of get_int
:
int x;
prinf("x: ");
scanf("%i", &x);
prinf("x: %i\n", x);
for get_string
:
char s[5];
prinf("s: ");
scanf("%s", s);
prinf("s: %s\n", s);
// C does come with a pointer type FILE
// that... 🥁 points to a file
FILE *file = fopen("phonebook.csv", "a");
// always check for NULL
if (file == NULL)
{
return 1;
}
This is how you define a BYTE
:
typedef uint8_t BYTE;
🤔 How do you recognize a jpg file?
The first three bytes of any .jpg
files are: 0xff
, 0xd8
and 0xff
.
🤔 What is a bitmap?
A map of bits 🥁
And, finally, this is how you copy a file, one byte at a time:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 3)
{
fprintf(stderr, "Usage: copy SOURCE DESTINATION\n");
return 1;
}
// open input file
FILE *source = fopen(argv[1], "r");
if (source == NULL)
{
printf("Could not open %s.\n", argv[1]);
return 1;
}
// Open output file
FILE *destination = fopen(argv[2], "w");
if (destination == NULL)
{
fclose(source);
printf("Could not create %s.\n", argv[2]);
return 1;
}
// Copy source to destination, one BYTE at a time
BYTE buffer;
while (fread(&buffer, sizeof(BYTE), 1, source))
{
fwrite(&buffer, sizeof(BYTE), 1, destination);
}
// Close files
fclose(source);
fclose(destination);
return 0;
}
]]>O(n)
- on the order of n🤔 And what's in the opposite end of Big O?
Ω
Greek Omega letter used to describe the best-case scenario (Ω of ...)for i from 0 to n-1
If i-th element is "value you are looking for"
return true
return false
if no items
return false
if middle item is "value you are looking for"
return true
else if "value you are looking for" < middle item
search left half
else if "value you are looking for" > middle item
search right half
==
to compare two strings (yes for int
and yes for char
)strcmp()
found in <string.h>
file🤔 What's a hertz?
🤔 What is a struct? It's a container inside which you can put multiple other data types.
// define the struct
typedef struct
{
string name;
string number;
}
person;
// initialize the array people with length of two
// using the person struct
person people[2]
// assign value
people[0].name = "Eva";
people[0].number = "123-456-789";
for i from 0 to n-1
find smallest item between i'th item and last item
swap the smallest item with the i'th item
Repeat n-1 times
for i from 0 to n-2
if i'th and i+1'th elements out of order
swap them
if no swaps
Quit
if only one item
return
else
sort left half of items
sort right half of items
merge sorted halves
🤔 How do the algorithms compare In terms of running time (slowest -> fastest)?
In terms of Big O:
O(n2)
bubble sort, selection sort, insertion sortO(n log n)
merge sortO(n)
linear searchO(log n)
binary searchO(1)
In terms of Ω:
Ω(n2)
selection sortΩ(n log n)
merge sortΩ(n)
bubble sort, insertion sortΩ(log n)
Ω(1)
linear search, binary searchfor describing algorithms where O
andΩ
values are the same
θ(n2)
selection sortθ(n log n)
merge sortθ(n)
θ(log n)
θ(1)
A function calling itself.
Classic example is the factorial:
fact(n) = n * fact(n-1)
Every factorial has two cases:
int fact(int n)
{
if (n == 1)
return 1;
else
// With single line returns, you can take the curly braces away.
return n * fact(n-1)'
}
]]>make hello.c
you get a file called a.out
(aka assembly output).clang -o hello hello.c
clang
where to find it: clang -o hello hello.c -lcs50
(link in the cs50 library)Compiling actually involves four steps:
Syntactic errors vs logical errors.
printf
debug50
(a debugger built on the industry standard's tool called GDB - the GBU debugger)
// this is inside CS50 IDE
bool 1 byte (bit wasteful, could be just a bit instead)
char 1 byte
double 8 bytes
float 4 bytes
int 4 bytes
long 8 bytes
string ? bytes
With an array declaration, you need to specify three things:
int scores[3];
And this is how you pass an array as an input:
// you use square brackets, but no size
// arrays in C do not know how long they are
// so you'll need to pass in length separately
float average(int length, int array[])
What is a (damn, you) segmentation fault ?
🤔 What is the difference between conversion, casting, coercion?
How do we know when the string ends?
\0
null (terminating) character where you basically "waste" one byte to indicate where the string ends.string
with length
3, actually takes up 4 bytes.
// since every string end is padded with the NULL char
for (int i = 0; str[i] != '\0'; i++) {}
// can be replaced with strlen
// make sure to include the <string.h> header
for (int i = 0, len = strlen(str); i < len; i++) {}
Food for thought 🤔
argc
: argument count. The program's name is by default, the first argumentargv
: argument vector (vector is another word for array
), is an array of strings. The first element argv[0]
is always the name of the program. The last element is always stored at argv[argv-1]
main
returns 0.int main(int argc, string argv[])
{
printf("hello, %s\n", argv[1]);
}
else
{
printf("hello, world\n");
}
return 0
return 1
echo $?
🤔 What is the difference between function declaration vs function definition?
float sum_two (int a, int b);
// the definition (aka the actual recipe)
float sum_two (int a, int b)
{
int result = a + b;
return result;
}
void
) arguments or no output (also void
).clang
) -> machine code (binary)clang -o hello hello.c -lcs50
-> make hello
.h
refer to some other set of code, like a library, that we can then use in our program.console.log
something in C:// a library that allows you to get user input
#include <stdio.h>
int main(void)
{
printf("hello, %s\n", answer );
printf("%i\n", x + y);
}
bool
for true
or false
char
single ASCI characters: take up 1 byte (8 bits)int
number: always take up 4 bytes (32 bits) of memory (meaning that you can't count higher than ~ 4 billion)int
is a qualifier - it doubles the positive range of values that an integer can take on (but doesn't allow for negative values). There are also other qualifiers like short
, long
(64 bits), and const
long
really big numberfloat
number with decimals, take up 4bytes (32 bits) of memory, caution: there's a limit to how precise we can be with floatsdouble
number with many decimals, up to 8 bytes (64 bites) of memorystring
(must #include <cs50.h>
)In computing, the world was created on January 1, 1970. Computers have been counting time in seconds since the. On the specified date, the seconds will overflow the 32-bit integer (after 4 billion seconds have elapsed) and the computers will start counting in negative. In short, the Year 2038 problem is caused by an insufficient number of bits chosen to represent time.
structs
(structures)typedefs
(defined types)🤔 How about void
?
void
is a type, but not a data type:void
return type, which means they don't return a value (like printf
)void
as parameters simply take no parameter%c
char (make sure to use single quotes for char
)%i
int (integers are truncated floats! Everything after the period goes away.)%f
float, double%li
long%s
string// converting one of the ints is enough
float z = float(x) / y;
&&
, ||
, !
, relational operators: >
, >=
, <
, <=
, ==
, !=
)if
, else if
, else
switch
statementwhile
, do while
, for
void main(void)
<- type of inputvoid meow(void);
ls
, cd
, pwd
, mkdir
, cp
, rm
, mv
🤔 What is a greedy algorithm?
Note: I've published this post previously, but I'm rewatching the CS50 lectures again and updating the old notes as I go along.
🤔 What does binary mean?
Binary is the numbering system that computers use in order to represent on and off. On is 1, and off is 0. It's a base 2 system.
Computers take in the electricity as the input and use that to harness and keep track of information. Store some electricity to represent 1, and let go of some to represent 0.
Modern computers use a million tiny switches called transistors that can be turned on and off.
A single digit (either a 0 or a 1) in binary is known as a binary digit. Or, simply, a bit.
so 110010 in binary, is 50 in decimal
in ASCII standard, letter A is represented by number 65, or 01000001 in binary
8 bits (8 digits) represent a byte, representing 256 different values
but to write accented letters, Asian characters, or emojis, you'll need to use 16, 24 or 32 bytes instead (there's where Unicode steps in)
Unary is a system where each digit represents a single value of one.
🤔 How about 8-bit vs 16-bit machines?
rgb
.png
, jpg
, .gif
) is just people agreeing how to store patterns of zeros and ones in a file.input -> algorithms -> output
🔗 Extra stuff researched by me mostly based on this article.
🤔 And what is encoding?
Encoding is a standardized way of translating between two things.
ASCII encoding is a set of rules that allows us to translate certain characters into decimal numbers.
ASCII can represent every character using a number between 32 and 127. Space is 32, the letter “A” is 65... These can be stored in 7 bits (meaning numbers 128 - 255 were up for grabs). Codes below 32 were for control characters.
In the ANSI standard, everybody agreed on what to do below 128, which was pretty much the same as ASCII, but there were lots of different ways to handle the characters from 128 and on up, depending on where you lived. These different systems were called code pages.
🤔 What is UNICODE?
UNICODE is a superset of ASCII
Unicode was an effort to create a single character set that included every reasonable writing system on the planet and some make-believe ones like Klingon, too.
In Unicode, a letter maps to something called a code point.
Every platonic letter in every alphabet is assigned a magic number by the Unicode consortium, which is written like this: U+0639. This magic number is called a code point.
Hello
is an equivalent of U+0048 U+0065 U+006C U+006C U+006F.
🤔 What is UTF-8?
UTF-8 was another system for storing your string of Unicode code points in memory using 8-bit bytes.
In UTF-8, every code point from 0-127 is stored in a single byte.
Only code points 128, and above are stored using 2, 3, in fact, up to 6 bytes.
This has the neat side effect that English text looks exactly the same in UTF-8 as it did in ASCII.
Greek is not my first foreign language, nor is it my first self-taught foreign language. Readers of this blog will remember my 6-month Spanish fluency experiment, which I'm excited to say, after ten months, is still ongoing... 😬
When it comes to languages so far, I know:
There's also French, which I learned in high school for four years, but it never really stuck with me. Mostly, I think that's because I had shitty grades, and all the teachers told me that I sucked at languages, so I was rather half-assing it. Admittedly, I was also rather laissez-faire with placing those letter stresses, which irked my professor greatly and forced her into early retirement. True story.
This is just to say that when it comes to learning a foreign language, there's definitely no magic pill that will make you pick up a new language every three months or so. Talent is overrated, and in the end, it usually comes down to your motivation and the hours you put in. (Spoiler alert: it takes a long long time).
Besides studying languages, I also spent quite a bit of time teaching languages. While in China, I taught English (mostly adult 1:1 classes) to Chinese people and taught Mandarin Chinese to ex-pats. I also wrote lessons and podcasts for an online language course. Later on, I wrote a couple of books on self-learning Chinese and even hosted a 12-week Chinese language boot camp!
Yeah.
Meaning, that luckily I do have some ideas on how to approach this. And this is how:
Spend 10 minutes googling about the language and try to answer things like: Does this language have any relatives? How many speakers? How does the grammar look like? How hard is it?
🇬🇷 This is what my notes on Greek looks like:
Time to get a little bit more detailed: What letters does the language have? How do you pronounce them? How do you write them down? How do you input them (via a computer keyboard)?
🇬🇷 The Greek alphabet consists of 24 letters, some of them with rather interesting choices for uppercase and lowercase variants. It's both familiar and infuriatingly confusing at the same time.
It makes me think of my mom trying a michelada for the first time. We took her to an authentic Mexican restaurant, and we ordered her one. She saw beer, thought, hey, I know that! and went right into it. The look of surprise/confusion/disappointment that followed just a second later - that's how I feel about learning the Greek alphabet.
So, for example, the first shocker was the fact that the letter B (you know, the good old beta β) is actually pronounced as v (like Victor) - all my life, a lie!
By some sort of twisted logic, this means that the Greek letter that looks like ν is pronounced like n. Hah!
There's more: Uppercase H is pronounced as Ι (like in 'igloo'). The same letter in lowercase looks like this η (suspiciously a lot like an n!), but, plotwist! it's still pronounced like an i!
And then there's also a bunch of diphthongs and two letter consonant which are even more deceptive and not to be trusted.
Needless to say, I'm still in the 'alphavet' stage. 🥁
I learned how to pronounce the alphabet here and here. I practice my alphabet and reading on Duolingo and here (such pretty flashcards! ☺️).
This is super important as it gives you a better idea of how the language sounds and also gives you an opportunity to get some early feedback on how you're doing.
I'd listen to the original recording and then repeat, trying to imitate the sound and the stress. If you can record yourself and (cringe) playback later, even better.
If you can utter your baby-steps Greek live to someone's face (preferably a native speaker who knows what's what), you've basically made it and you can slack for the rest of the day!
🇬🇷 The vocabulary portion takes me around 30 minutes each day, which I spend on Duolingo and Memrise. Also, did you know that Duolingo has a dictionary for each language combination? It's super handy!
For recording and playback, I really like Audacity.
It's essential to get some grammar rules in early on. As adult learners, we might not be as quick to memorize words as we used to be, but we are much better at understanding structures and making connections.
Things like rules for forming masculine, feminine, or neuter nouns. How do the verbs change when you use them for different people? Are there articles? How do adjectives and nouns work together?
Luckily I have quite a solid grammar foundation from my university days, but even if you don't, Language Transfer offers free audio courses and is an excellent resource for learning about grammar and sentence structure.
🇬🇷 Language Transfer Greek has 120 lessons, and I'm 20 lessons in. I listen to an episode or two a day, typically during 🐕 walks which is neat because I get to confuse people with my Greek mutterings. Due to my Swiss cheese memory, I have to re-listen every lesson several times before it sticks, but that's alright, Mihalis from Language Transfer is plenty entertaining.
This is generally the fun-est part of learning a language. It's learning without really working that hard. It's allowing your interest and hobbies to take over; you can do anything as long as the content is somehow related to your target language.
This can be food, music, literature, food, movies, art, and did I mention food?
🇬🇷 We've watched My Big Fat Greek Wedding, which I was told is rather legit (the second movie wasn't that great). And I've also been:
If anyone has played the board game Santorini, let me know what you think of it.
I think this covers up the basic attack plan and summarises what I've been up to this past month.
My strategy is basically the same for the next month, except I want to add on a weekly 1:1 iTalki class. I'll let you know how it goes! 🤞
]]>Dearest creatures big and small, we are now more than six months removed from that bleary-eyed morning of January 1 (2021) when I proposed to my wife...
that we switch our conversations entirely (enteramentemente... mente) from English to Spanish.
"Trust me," I said, "it will be fun."
"No," she replied, "it won't be. For me."
And, as always, she was right.
More on our state of marriage further down, but first, a quick rundown of all the works done in the past month.
Duo the búho, and I, are still at it. By "it," I mean that we still have a quick ' n ' dirty 20-minute session first thing in the morning. It's confusing, random, and unsatisfactory.
As a result, I currently possess 1021 Crowns, a 210-day streak, and 984 lingots (which ever since dressing up my búho in a champagne tracksuit haven't really been of use to me).
I'm about to finish level 8, and there (seem to be) only nine levels in total, so, fingers crossed, I can finish it all up by September.
Oh, did I forget to mention I'm going to keep studying Spanish? Yeah... Because Dao, the journey, you know?
that búho is one of my least favorite words in Spanish. Also, almohada, which means pillow, but to me just sounds "wet" and "moist," all those things that pillows (ideally) shouldn't be. Seriously, who would want their face to be touched by a wet, cold, sticky, horrible almohada?
and to help with context-filling, I've also started this huge Memrise deck of Advanced Spanish. It's fun because now I know how to say things like taxidermist (disecador), catapult/sling (tirachinas), and other useful words. I'm a great cocktail-party conversationalist!
Cooficial means official. Why, Spanish, why? 💔
The only thing that I watched in Spanish this past month is the Netflix series Club de Cuervos. I know, I know, it's about football, which is just about the boringest thing one can watch; however, it's Mexican-made (mi gente), quick, funny, and easy to follow. I watched an entire season and then gave up - all the family back-stabbing was just too stressful to watch.
I've finished the rest of the YA literature that I could find at home, mainly:
Then I tried reading some of the serious books from my wife's side of the bookshelf, and I couldn't understand anything. First of all, there were no pictures, and secondly, my wife's taste in literature can be summarised as "big-words, no-periods." Actually, "big-words, no-periods, no-commas, and no dialogue". Just long, long sentences that end 13 pages later. In tears. Mine.
Anyway, I gave up and now I'm reading a boy-meets-girl rom-com in which this super successful 30-something woman is all confused, and shy, and Bambi-like and apparently knows nothing about anything (and especially nothing about herself). But! Fortunately, her Bambi-like cluelessness is super attractive to this dude 🙄🙄🙄 , and so all is well. She'll be saved, don't worry.
has a recommendation that falls between the above two genres, do let me know. 🙏
Something that I really like about reading in Spanish right now is that since I do understand some or even most of the words, but sometimes I am too lazy to get up and check the rest in the dictionary, I get to kind of choose what they mean instead - which can color things quite differently from the way the author intended.
For example, the word carcajear, in the context of she said something and he carcajear-ed. For the longest time, I thought that meant "to chuckle," like you know, me telling this brilliant joke and people politely chuckling along (because they are in our house, and we just served them food and fancy booze, and so they should!).
Anyway, so I finished this one book (prolly one of the Agatha Christies) and felt quite sad that nothing truly spectacularly funny was ever being said since no one ever managed to muster more than a chuckle. #sadLife
It turns out, however! that carcajear means full-on laughter, like guffaw, ha-ha-ha, holding my belly, about to fall off my chair laughing. This kind of makes me happy because people (women even) in that Agatha Christie book were indeed hilarious. I just didn't get it. 😳
This month I "discovered" a bunch of cool Latino music!
Lastly, a new podcast that I'm currently listening to:
I think I'm just going to keep at it. Finish DuoLingo, then move on to spending more time in Memrise. Keep listening to Latino music and eventually tackle Valerie's mightly bookshelf.
Valerie has many movies that she wants to show me, and I have a bunch of Café Tacuba lyrics that I want to memorize.
I also bought The big red book of Spanish verbs - I'm hoping to go over it slowly so that by the time I'm an 80 something viejicita, I finally know how to use the future subjunctive.
I'll keep listening to Paco from Wisteria Lane during our lunch breaks and Ash & Letty from Se Regalan Dudas during the doggie walks.
I'll patiently read the Wikipedia articles in Spanish and keep choosing the wrong option every time my alarm clock asks me "to cancel" or "to snooze."
I'll keep talking to Valerie in Spanish even though some days we hate it and sometimes we even have arguments because I misunderstand her carcajadas. Because I think it made this covid life more fun, it made us closer, more patient and because, damn it, I managed to learn another language! 🏆
But,
most importantly... I'll keep eating all the tacos.
Final report:
Maybe? 🤷♀️
]]>The global scope is an important glue in practically every JS application.
In modern browsers, multiple JS files are stitched together using one of the three following ways:
export
what they want to be accessible from outside and import
what they need.files are typically concatenated together into one big file before delivery to the browser and JS engine
additional mechanism needed for resolving namespaces via a wrapper function
// this establishes an application-wide scope
// a stand-in for the global scope
(function wrappingOuterScope(){
var moduleOne = (function one(){
// ..
})();
var moduleTwo = (function two(){
// ..
function callModuleOne() {
moduleOne.someMethod();
}
// ..
})();
})();
🤔 But, what do build tools actually do?
<script type="module">
in HTML.import
calls with bundler functions, so that it works. Special module types like HTML/CSS modules are also supported.console
and debugger
removed.// the modules are dropped onto the global scope
// this is same as loading files separately
var moduleOne = (function one(){
// ..
})();
var moduleTwo = (function two(){
// ..
function callModuleOne() {
moduleOne.someMethod();
}
// ..
})();
undefined
, null
, Infinity
, NaN
Date()
, Object()
, String()
, etc.eval()
, parseInt()
, etc.Math
, Atomics
, JSON
Intl
, WebAssembly
console
(and its methods)window
, document
, etc)setTimeout(..)
, etc)navigator
, history
, geolocation, WebRTC, etc.🤔 And what about Node?
Node also exposes several elements "globally," but they're technically not in the global
scope: require()
, __dirname
, module
, URL
, and so on.
// In a browser, global functions and variables
// declared with var (not let/const!) become
// the property of the global object
var studentName = "Kyle";
function hello() {
console.log(`Hello, ${ studentName }!`);
}
hello();
// Hello, Kyle!
// The variables will be loaded as properties on
// the `window` object (so you can do `window.hello()`)
the code may be loaded via:
<script>
tag<script src=..>
tag in the markup<script>
❗ Using global variables is generally discouraged. There should be as few global variables as possible.
🤔 We use the global object to test for support of modern language features.
if (!window.Promise) {
alert("Your browser is really old!");
}
window.something = 42;
// let declaration adds a something global variable but not a global object property
// something lexical identifier shadows the something global object property
// avoid this confusion by using var for globals (and let and const for block scopes)
let something = "Kyle";
console.log(something);
// Kyle
console.log(window.something);
// 42
To make our code future-proof and easier to understand, we should access properties of the global object directly, as window.x
🤯 a DOM element with an id
attribute automatically creates a global variable that references it.
<ul id="my-todo-list">
<li id="first">Write a book</li>
..
</ul>
first;
// <li id="first">..</li>
window["my-todo-list"];
// <ul id="my-todo-list">..</ul>
var name = 42;
// because name is actually a pre-defined getter/setter on the window object,
// which insists on its value being a string value
console.log(name, typeof name);
// "42" string
Web Workers are a web platform extension on top of browser-JS behavior, which allows a JS file to run in a completely separate thread (operating system-wise) from the thread that's running the main JS program.
It does not share the global scope with the main JS program.
In a Web Worker, the global object reference is typically made using self
.
var studentName = "Kyle";
let studentID = 42;
function hello() {
console.log(`Hello, ${ self.studentName }!`);
}
self.hello();
// Hello, Kyle!
self.studentID;
// undefined
There are differences in:
let
/ const
) when used in the outermost scope// variables declared inside a module, are not trully global
// they are module-global
var studentName = "Kyle";
function hello() {
console.log(`Hello, ${ studentName }!`);
}
hello();
// Hello, Kyle!
export hello;
.js
file as a module (either ES module or CommonJS)// the var and function declarations are contained in that wrapping function's scope,
// and are not treated as global variables
var studentName = "Kyle";
function hello() {
console.log(`Hello, ${ studentName }!`);
}
hello();
// Hello, Kyle!
module.exports.hello = hello;
global
object.global
is a reference to the real global scope object, somewhat like using window
in a browser JS environment.global.studentName = "Kyle";
function hello() {
console.log(`Hello, ${ studentName }!`);
}
hello();
// Hello, Kyle!
module.exports.hello = hello;
globalThis
that should be supported across all environments. It’s supported in all major browsers.Remember how back in January I said that I'm giving myself 6-months of daily Spanish grind to achieve some sort of advanced level of Spanish? By June? Of this year?
Well, it's May, people, and although we're somewhere, we're definitely not there yet. #understatementOfTheYear
This past month was difficult. I blame it on the nice weather, which meant that I spent a lot of time walking outside and recuperating from my post-ice-cream sugar comas.
It didn't help that Valerie's work was extra estresante (see what I did there?), which meant switching to English for entire days.
And, also, sometimes it's just nice to utter something the way you actually meant it and get yourself understood. It's just so much easier. And faster.
Did you know that in Spanish, a discusion is an argument? (as if you can't have a conversation in Spanish without yelling at each other?). Anyway, once I told Valerie that I was having a discusion with this person and then later a discussion with that person and she was like, "are you having your period or something", and I was like, "no, and stop saying that". "I'm birthing a blood diamond". (ya, I know).
Valerie and I are swell btw.
I was given homework! Well, Valerie refused to speak more Spanish with me until I sit down and practice the difference between por and para, which I've been using very nonchalantly until then. So I did.
Just so you know, I'm not trying to be difficult. Both of these words do actually mean (among other things) "for".
A lot of folks out there trying to learn Spanish (native English speakers in particular) have problems pronouncing the Spanish R. That's the sound you are supposed to make when someone does something sexy (like when men do the dishes or something), you know the 'rrrrr' accompanied with a tiger claw. Cause tigers are sexy. Or something.
I like that I can do the rolling R (and not just because I have dish-washing men in my life) and that I can generally pronounce whatever Spanish throws at me. So, there is, as they say, that.
I watched some more Cable Girls (continuing from the last month), but in the end, it was just too much drama, so I gave up after eight episodes or so. No other TV or movies in Spanish, but I did watch some random, weird YouTubers:
Magrat and I continue to study Duolingo every morning. Magrat helps to answer by sitting down on the trackpad. Or sometimes, she makes things more difficult by parading her naked, hairy body in front of my screen. Perhaps it should be established that Magrat is a cat.
I'm sort of getting bored by Duolingo, so I've scaled it down from 5 daily lessons to 3-4. The grammar lessons are still super useful, but some of the vocabulary I just can't be bothered with.
There was this chapter about football that was tough and had like nine thousand words to say "kicking". Who cares? Just pass the ball! But I suppose I must get the Duolingo Golden Tree, so I shall continue. Until I die. Or Magrat finally decides that I've been hogging the computer for too long.
I've started using Memrise to up my vocab game. It's super neat that you can select decks that use Mexican Spanish (which is what I'm supposed to speak) and thus avoid Wife saying things like: "Eva! No tortillas for you!"
I read five books in Spanish: 3 Agathas, a YA book, and a book about hostage negotiations (you know, for if we ever decide to have kids).
After the funearal: Despues del funeral
The Murder at the Vicarage / Muerte en la vicaria
Endless Night / Noche eterna
Never split the difference / Rompe la barrera del no (Chris Voss) - really good book about negotiation skills
Second Star to the Right / Segunda estrella a la derecha (Deborah Hautzig) - a book about teenagers and anorexia and it's horrible
Some more thoughts on Agatha. As regular readers will know, I've read a lot of Agatha. Once upon a time, I even had an Agatha Project - where I was trying to read all of her books without buying a new one (either by borrowing copies, picking them up from libraries, or buying them secondhand).
Her books are clever and funny and sometimes utterly surprising. The stories where the narrator turns out to be the murderer are my favorite! (Because, in the end, don't we all... sometimes...)
As a woman, I also find it generally inspiring that she managed to thrive in a world dominated by ben - I got to stan that.
But, but, the more I read, and, I suppose, the more I get to actually understand what I read, the more frustrated I'm getting with all of the woman put-me-downs.
Her novels are littered with descriptions like this: "Oh, yeah my wife, you know she's a lady woman and has been afflicted by this lady woman illness, very sad, probably bed-ridden for life. The usual light headaches, hysteria, and weakness of the mind. Probably best not to listen to her and just discard everything she says, okay?" Wot?!
To be clear, she's also not great with 'forn' people: Hercule Poirot is always described as this weird, unimpressive almost-French man, but come on!
Anyway, I think we have broken up.
Two good finds in the past month:
Spanish is hard.
]]>Here are the highlights.
Okay, confession time, this wasn't the most professionally organized conference on the planet. It was my first ever zoom conference, so much so that I was googling "how to make zoom co-host" 30 minutes before the kickoff.
After not having done meetups, streaming, or larger events for a while, I was feeling a little bit rusty.
Most of the conference organization happened one week before, but luckily it all worked out fine and dandy because everyone said yes (my requests come with lots of exclamation marks).
The speaker rehearsal
I asked all the speakers to show up 15 minutes in advance, which gave us enough time to test everyone's setup (microphone levels, sharing screen) and make sure that things went smoothly.
The moderators
It was great having two lovely moderators to help with the chat and getting people into zoom—one less thing to worry about.
The duration
The duration and the number of speakers felt right (it took us around 2 hours). Having a 5-minute break was a great idea, too (not to mention elevator music right there at the press of a button). And, obviously, the banner!
The banner deserves its own subsection because it was amazing. So here's what happened (this is around 20 minutes before the conference, right):
Valerie: so, Eva, what's your website again?
Eva (agitated): includejs dot dev.
(makes note to get Valerie an includeJS tshirt)
V: Right. Got it.
E: (frown)
(makes note to ask Valerie to design the includeJS tshirt)
V: Can you send me your conference banner?
E: Huh?
(panic. does the absence of a banner mean that we are not a real conference?)
V: The conference banner. For the conference?
E: I don't have that.
(remembers that Valerie knows how to design stuff)
E: Can you make me one? 😬
V: Sure. I will. Because you are amazing.
The banner was heavily featured during the conference break and was, I believe, what made this mini-conf a success in the end.
Invite only
Having the event as an invite-only was, I thought, a great idea. This meant that we wouldn't have to worry about intruders and also gave me the opportunity to collect a bunch of new emails that I can now spam with my Awesome Ideas.
The talks
More on that below.
The questions
Every (15-minute) talk was followed by a Q&A session which always resulted in a lively discussion that sometimes carried over in the chat. Having the chat sidebar was great, too, because it allowed everyone to be able to contribute. I think by the end of it, everyone had chimed in one way or another.
Mixing talk types
I think it would be great to mix longer talks with lightning talks. If we get to do this again, I'll also try to encourage first-time speakers to contribute. CFP style.
Networking
For me, the best part of a tech conference (besides no queues during toilet breaks) is hanging out with people and meeting new peeps. However, I have no idea how this could be done well in Zoom (maybe a dedicated breakout session), but I think it would be a nice thing to have. Especially if we have more people next time.
Pomp and circumstance
I'm talking stickers. Tshirt. Mousepads. Keychains. Tattoos. The whole shebang. But that does mean sponsors and money and sigh...
Also, the conference ended rather abruptly 🤔 I'm an efficient goodbyer - I have to be, the Mrs is extremely bad at this and just keeps faffing about not knowing how to finish - so the conference ended in the Eva-style of: "Okay, goodbye now." It would be nice to have a more grandiose goodbye.
I'm talking fireworks. Timpani. Tattoos. The whole shebang.
(huh, does this shebang have anything to do with the bash shebang. Ugh, if only there was a way to find out...)
I received a ton of positive feedback after the conference, with all of the comments raving about two things: the quality of the talks and the super welcoming community (and The Banner, of course!). I'll say more about the talks further down, so let me start with the community.
The includeJS community
is awesome. It's full of nice and kind and smart people that want to help each other get better. It's about learning and supporting each other and having fun. Or listening to others when they are having a bad day or just need to vent.
I asked our members to also invite their friends and coworkers, and they did. This resulted in having even more nice and friendly, and awesome people. "Wholesome" is what one feedback said. "You have something good going on there", said another. includeJS 4ever (#tattooIdeas)
I was really impressed by our speakers and how their talks complemented each other. We talked about dev ops, 11ty, building a privacy-minded application, and upskilling yourself by teaching others.
Three of the talks were from our community members, and Stephanie showed up to show us The Way of 11ty", because she's awesome.
Special thanks to Elisabeth, who was the first one to agree to do a talk and basically kickstarted this whole thing.
If you are on Twitter, I definitely recommend you to follow these awesome ladies.
@elisabethirg - wtf is DevOps anyway?
@5t3ph - Introduction to 11ty (livecoding)
@raae - Building POW!; privacy first
@britnorcodes - Levelling up by teaching others
I would love to have a physical (as in, not violent or anything), a 3D, in your face (I mean, I don't mean like super loud), we-shall-all-be-in-the-same-room includeJS conference at some point, but probably not this year - it doesn't seem like we're there yet.
So, maybe baby includeJS mini-conf could happen again.
]]>var studentName = "Suzy";
// the parameter is shadowing the (shadowed) global variable.
function printStudent(studentName) {
studentName = studentName.toUpperCase();
console.log(studentName);
}
printStudent("Frank");
// FRANK
printStudent(studentName);
// SUZY
console.log(studentName);
// Suzy
let
can shadow var
, but var
cannot shadow let
.window
) object - when declared with var
or function
var studentName = "Suzy";
function printStudent(studentName) {
console.log(studentName);
console.log(window.studentName);
}
printStudent("Frank");
// "Frank"
// "Suzy"
But what is the difference in the name?
// a named function expression
var askQuestion = function ofTheTeacher(){
// ..
};
// ofTheTeacher is declared as an identifier inside the function itself
var askQuestion = function ofTheTeacher() {
console.log(ofTheTeacher);
};
askQuestion();
// function ofTheTeacher()...
console.log(ofTheTeacher);
// ReferenceError: ofTheTeacher is not defined
// defined as read-only
var askQuestion = function ofTheTeacher() {
"use strict";
ofTheTeacher = 42; // TypeError
//..
};
askQuestion();
//
// an inferred name
var askQuestion = () => {
// ..
};
askQuestion.name; // askQuestion
]]>💡 Quick reminder
The term "lexical" refers to the first stage of compilation (lexing/parsing).
Scopes are determined during compilation based on where the functions/blocks of scope are written, the nesting inside each other, and so on.
Each scope bubble is entirely contained within its parent scope bubble—a scope is never partially in two different outer scopes.
References (non-declarations) to variables/identifiers are allowed if there's a matching declaration either in the current scope or any scope above/outside the current scope, but not with declarations from lower/nested scopes.
Engine: responsible for start-to-finish compilation and execution of our JavaScript program.
Compiler: one of Engine's friends; handles all the dirty work of parsing and code-generation.
Scope Manager: another friend of Engine; collects and maintains a lookup list of all the declared variables/identifiers and enforces a set of rules as to how these are accessible to currently executing code.
2a. (featuring Compiler & Scope Manager) on encountering a variable declaration, the first step is checking with the Scope manager if the variable already exists; if so, do nothing; if not, stick a pin and, at execution time, ask the scope manager to create a new variable
2b. (featuring Engine & Scope Manager) compiles the code for the Engine to execute, the engine will check with the scope manager for where it can find the variable and initialize it (+ declare value, execute)
The compiler also signals when it runs across functions or block scopes so that a new scope bucket and Scope Manager can be instantiated.
var
is declared value undefined
but not const
/let
)What happens if we can't resolve an identifier?
ReferenceError
(not defined, but not undefined
- which is a variable that has previously been declared but otherwise has no value)😵 This is confusing:
var studentName;
typeof studentName; // "undefined" - makes sense
typeof doesntExist; // "undefined" - doesn't make sense, should be `not defined`
If strict-mode
is disabled you can get an accidental global variable
function getStudentName() {
// assignment to an undeclared variable :(
nextStudent = "Suzy";
}
getStudentName();
console.log(nextStudent);
// "Suzy" -- oops, an accidental-global variable!
]]>Answering the following two questions:
But also:
In classic compiler theory, a program is processed by a compiler in three basic stages:
tokenizing/lexing: breaking up a string of characters into meaningful chunks, called tokens
parsing: taking a stream (array) of tokens and turning it into a tree of nested elements, which collectively represent the grammatical structure of the program (aka Abstract Syntax Tree or AST)
code generation: taking an AST and turning it into executable code.
🤔 Oi, but what is the difference between tokenizing and lexing?
JS engine first parsing the entires program before any of it is executed and throws syntax errors if something isn't right.
function saySomething() {
var greeting = "Hello";
{
greeting = "Howdy"; // error comes from here
let greeting = "Hi"; // because let lands you in the TDZ
console.log(greeting);
}
}
saySomething();
// ReferenceError: Cannot access 'greeting' before
// initialization
Now for the compilation bit: it makes sense that once JS is converted into AST (previous step), it is then compiled into its most efficient (binary) representation for the engine to execute.
variable ? target : source
students = []; // students
for (let student of students) { // student
getStudentName(studentId) // studentId
function getStudentName(studentID) { // getStudentName
for (let student of students) { // students
if (student.id == studentID) // both student and studentID
return student.name;
getStudentName(73) // getStudentName
console.log(nextStudent) // both console and nextStudent
let
and const
), then it's associated with the nearest enclosing { .. }
block, rather than its enclosing function (as with var
).global
or find nothing - aka undeclared
).📺 Previously: Updates from the 1/2 down the line
I'm skipping the self-assessment bit for this month because I have no idea where things are at at the moment. Some days (moments) I'm just brilliant, and I get it all, and then other moments (days) I am committing the same stupid error for the 100th time, and everything is just so hard and slippery...
My speaking, obviously, is still the worst, although I haven't had many opportunities to do much writing yet, except for the occasional text exchange between the wife and I with the likes of (and this is paraphrasing): Where is food?
So what I've been focusing on most this past month (and it's so hard!) is slowing down. This means thinking before speaking (I know, kind of obvious, no?) and not feeling rushed when I do speak. Has it worked? 90% of the time, no 😊, But 10% of the time, I do manage to say something coherent.
I've also started having conversations with myself, imagining different scenarios, and practicing "now, how would I say this in Spanish? 🤔". Or I would take a moment and prepare a sentence or a question in advance so that when I do eventually come out with "the kitchen is on fire!" it does come out with the perfect grammar. 👍 (muy importante)
I'm still doing Duolingo every morning for about 30-40 minutes, but since I've finished all the Stories (aka easy points), I'm now only doing around 100 points per day. The content is also getting more difficult, and the sentences are getting super long a la: Give him the book that we bought yesterday at that market but don't give it to him today. Yes, we get it Spanish; pronouns are hard!
More specifically, I've just finished checkpoint 6 out of (currently) 9. I originally thought there were only 7, but once I finished checkpoint 5, more levels automagically appeared.
So now I have no clue and am collecting predictions: which one will finish first, my affair with Duolingo OR, the pandemic (for simplification purpose: travel without restrictions)?
OR! Neither of them will finish and this is it, this is my life? 😳
I've been listening to lots of slo-mo Spanish: first, Notes in Spanish (around 40 episodes 10-15 minutes each), and now Spanish obsessed (I'm currently level 22/34). Both podcasts have similar formats: a British guy and his co-host (a Spanish mujer in one case, a Colombiana in the other) discuss stuff in Spanish.
It rather concerns me that dudes are still making a bunch of mistakes when speaking (even after having lived in Spain for years), but I guess it's cool that I'm making the exact same mistakes now...
(this sentence is interrupted by my wife coming over to show me that she made tofu and that said tofu is "mucho mas cremoso que el otro" 🤷♀️)
...anyway, I guess it's comforting that I'm making the same mistakes as those advanced speaking-level dudes. Or is it? 🤔
I've read lots of books this past month, most of them in Spanish.
You'll notice that there's quite a lot of non-fiction there, which is rather odd for me (I rather prefer reading fiction). The reason is that non-fiction is just easier to understand because the vocabulary repeats much more, the language is more straightforward, and you don't have to keep track of who else is left on the ship, who's going to die next, and who is the 🔪🔫🤮(poison) after all (👀 at you Agatha Christie).
DeepL - like Google Translate, but better. You can install it locally as a macOS application and have it run in the background. It also comes with some nifty shortcuts, and so every time I copy some text and press cmd + c + c
(hitting the c twice), the text gets automatically copied into DeepL and translated. Pretty cool.
Keep at it. Convince wife that eating more homemade Mexican food is ultra beneficial to my Spanish learning journey 🤔.
That's it. See you next month! 👋
]]>cmd + c
for copy or cmd + f
for find.
Another note: As the title implies, these shortcuts are for macOS. If you want to use them on a Windows machine, you might just get away with changing cmd
to ctrl
to get it working. Obviously, this won't be true for the Custom shortcuts (featured right at the end of this post). These will work only for me. Because I'm special (and mostly, because I set it up like so.)
Table of contents
You modify the shortcut inside the Keyboard/shortcuts/Screenshots
.
Shoutout to Stefan for telling me this.
cmd + ~
Toggle between different windows of the same app.
ctrl + down arrow
View All Windows Of The Current App
Triple-click text to select the whole paragraph. (Wat. How did I now know that? 😳)
Did you know that if you drag-n-drop a chunk of text onto your desktop this will create a .textclipping
file which you can then again drag and drop into other apps? Madness, absolute and utter madness!
Excellent for copying frequently-used text (spells, incarnations, that sort of thing).
cmd + 1
To open Icons view
cmd + 2
To open List view
cmd + 3
To open Columns view
cmd + shift + .
Show hidden files (dotfiles) inside any finder window or file open dialog.
cmd + shift + h
Home directory.
cmd + shift + a
Applications directory.
cmd + shift + d
Desktop directory.
cmd + shift + g
Go to a directory (with autocomplete)
cmd + w
Closes the active window you are currently in. Use Option-Command-W to close all currently active app windows.
cmd + m
Mimimize. Aka hide in dock.
cmd + option
Hold these two then click on the app icon (in the dock) to get to all the open windows for a specific app. The rest of the apps get hidden.
cmd + shift + /
Focuses current application help search field - useful for finding hidden settings (inside text editors etc).
cmd + click
(on a link)To open it in your default browser.
cmd + ,
For preferences.
cmd + .
Often times works as "cancel".
ctrl + click
For bringing up context menus.
enter + shift
Add a new line (instead of sending) - most used in Messages and Slack.
cmd + 0
To return to the default (100%) zoom (most used in browsers).
cmd + e
Select a word, then use it as a search query.
cmd + g
Navigate through each instance of the item you want to find. This is waaaaay better than using that tiny dropdown arrow for going to the next search.
(from the TV series Dexter, doggy dude, very quick with hiding his apps/windows/tabs every time someone unexpectedly barged into his office. )
cmd + ctrl + q
Lock your machine, a must when working in a non-home environment (or working on secretive birthday plans).
cmd + h
To hide an app (it's still opened), but unlike minimize, you don't have it seen opened in the dock (to the right of that vertical bar).
I have that wired to:
caps lock + m
Forward delete:
caps lock + backspace
No, but seriously, I don't watch YouTube that much, but when I do, it's mostly tutorials and conferences, and sometimes people waffle a lot!
When I'm in learning mode, I also like to take notes, and this is where quick pausing and going back 10s is really handy (pun intended!).
Or sometimes you just want to skip ten seconds ahead because there's clapping or people are faffing around with their cables or something.
Anyway, below I collected the list of my favorite YouTube keyboard shortcuts, and I also added a couple of my recommended privacy settings (controlling what other people can see about you and, of course, deleting embarrassing videos from your history).
These are my favorite shortcuts and basically where my fingers are positioned by default when I'm watching a YouTube video, hit:
k
to play or pause
j
to rewind 10second
l
(as in lower-case L) to fast-forward 10 seconds
If you want to skip around and quickly navigate through the video, you can use any of the number keys (1
-9
) to go to that percentage (times 10) of the video.
For example: if you hit 6, you'll jump to 60% of the video, 9, is 90% etc.
If you want to move through the video frame-by-frame (like they do in CSI shows! now zoom in! yes, I can see the license plate now 🤷♀️), you'll need to first pause the video and use comma ,
and period .
keys to move backward and forward.
I watch most YouTube tutorials on 1.5x speed (for conference talks, you can go up to 2x).
To change the playback speed, use:
shift + comma
(to decrease the speed)shift + period
(to increase the speed)hit 🥊:
f
for full-screen (hit f
again to untoggle the mode)
t
for theatre mode
there's also i
for the tiny window on the bottom-right (when you want to keep the the video in the background while still browsing YouTube)
Press m
to mute or unmute.
Use uBlock Origin to skip ads
If you want to make your viewing activity and subscription private, head over to the Privacy settings page and untoggle:
You can remove watched videos from your history on the History page.
You can also disable history or auto-delete it from your Google account YouTube settings page.
]]>Super quick recap: this is how I self-graded my Spanish at the end of the first two months:
The goal is to have them all at C2 (except for writing which I don't think I'll really practice).
To clarify, I obviously don't think that I'll be 💯 fluent by the time July (of this year 😅) comes. I also don't think that I'll completely stop studying. Rather, I'll stop spending hours each day and instead will focus more on maintaining 🔨 a decent level of Spanish long term.
The wife: she's still here, hasn't left me, and continues to "patiently" and with "for sure no eye rolls" explain stuff to me. I think secretly (not so secretly) she rather enjoys shouting my mistakes back at me. It's cathartic for both of us (but mostly her).
Duolingo: I still spend around 40min a day and am currently halfway through level 4 (out of 7 levels). It's looking like I'll finish at some point in May. After that - once my tree is all gooooooldeeeeen 🌈 - I might give that time to Memrise and/or Clozemaster. You know, so that I can still pretend I'm studying super hard.
Language Transfer: still my favorite source for grammar. I've finished listening to the entire series (90 tracks, around 10 minutes each) for the second time around. I'm aware of more tenses than before, which I suppose is a start. I still have no idea how to use them (especially on the spot with my wife's unblinking stare directed right at me). You have no idea how many of my sentences still start with, "Yo dot dot dot. dot dot." 😭 I wish I could excuse them all as dramatic pauses, but then I guess just wanting some ice-cream isn't overly dramatic.
Spanish news radio: because my favorite thing to do over lunch break is to get confused. Also, Spanish (from Spain) newscasters are so flirty (with each other and sometimes with their guests!). And smoking seems to be very hip among announcers, too (geez, super throaty lady, get a lozenge already!). Sometimes I listen to a news segment for 10 mins, and I have absolutely no idea what's going on. Who did what? Where? Why are we listening to this? No idea.
My phone is still in Spanish, and so is my running/cycling watch - which is unhelpfully pronouncing Spanish words with a voiceover that I'm pretty sure is in American.
Because one has to have focus, or so says the book that I'm currently reading called Enfocate! (I wish!), for the past month, I've been focusing on two things: vocabulary and (horrible, horrible) irregular verbs.
To up my vocabulary and escape the classroom-land, I've started consuming more content in Spanish, either as podcasts, series/movies (aka whatever I can find on Netflix), or books.
These are the podcasts I'm currently listening to:
Racion de Nba - two dudes talk about NBA basketball. "Cancha" means a court, which is better than "concha", which means "shell", but also the ladies' underbits. (You will thank me next time you find yourself in Disney's Journey of the Little Mermaid ride, only to be greeted with "Bienvenido a la concha...")
La nota roja - the topic is femicides in Mexico. I only listened to one episode - because I like to sleep, thank you very much - but this is top-notch investigative journalism meets dramatic naration.
¡Con amor, carajo! - with the tagline "self-help stuff for women that don't like self-help stuff" and a curse word right there in the title, this is currently my favorite.
Se regalan dudas - two ladies talk about stuff. I haven't gathered much more than that. Also, sometimes there are guests. In every episode, we realize that we should Be Grateful 🙏.
Speaking of vocabulary, do you know how crocodiles are called in Spanish? "Cocodrilo". Co-co-drilo. Neta Spanish, neta?
These are the books I read in Spanish since last we met.
Spanish irregular verbs are my nemesis. First off, I keep messing up the two "to be" verbs (ser and estar) which is annoying. It's not that I don't know the difference, it's just that I probably talk faster than I think. #myFavoriteExcuse
I've recently started using ConjuGato - an app that helps you practice verbs and tenses. Also, did you know that there are a bunch of Spanish tenses that no one - not even my super learned wife 🤓 - uses? Yes, I'm looking at you, future subjunctive!
Due to lots of reading and listening to Spanish content, I think my comprehension skills have increased. My speaking and writing remain 💩. But! We'll get there!
Final report:
List directories only:
ls -d */
Quickly rename a file - one day, this will be me! 😎:
mv filename.{old,new}
Create a quick back-up copy of a file:
cp file.txt{,.bak}
Delete all files in a folder that don't match a certain file extension:
rm !(*.foo|*.bar|*.baz)
Remove all but one specific file 💪:
rm -f !(survivior.txt)
Convert filenames in current directory to lowercase:
rename 'y/A-Z/a-z/' *
Remove all spaces from all files in current the folder (super useful!):
rename 's/ //g' *
Diff two unsorted files without creating temporary files:
diff <(sort file1) <(sort file2)
Rapidly invoke an editor to write a long, complex, or tricky command. I've never really had the use for this one, but I dream of a day when I'll be writing bash
scipts...
ctrl+x + e
List of commands you use most often (there's also an oh-my-zsh
command that does the same, but I just couldn't find it... 🤔):
history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
3390 git
1179 g # alias for git
548 cd
333 go # git alias for checkout
321 j # alias for autojump
295 touch
270 npm
215 yarn
209 code # vscode
151 kill # oopsie lots of 🔪
Quick access to the ascii table (specifically, the decimal set 👍):
man ascii
Show File System Hierarchy:
man hier
Create a pdf version of a manpage
:
man -t manpage | ps2pdf - filename.pdf
Maybe useful 🤷♀️?Show apps that use internet connection at the moment:
lsof -P -i -n
Remove security limitations from PDF documents using ghostscript (untested 😅):
gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=OUTPUT.pdf -c .setpdfwrite -f INPUT.pdf
Get the biggest files/folders for the current directory:
du -s * | sort -n | tail
Shows size of dirs and files, hidden or not, sorted:
du -cs * .[^\.]* | sort -n
Remind yourself to leave in 15 minutes (note: To get rid of leave
you should either log off or use kill -s KILL
😬):
leave +15
Download all images from a site:
wget -r -l1 --no-parent -nH -nd -P/tmp -A".gif,.jpg" http://example.com/images
Save command output to an image:
ifconfig | convert label:@- ip.png
Easy and fast access to often executed commands that are very long and complex by using labels:
some_very_long_and_complex_command # label
=
var awesomeFunction = function(coolThings) {
// ..
return amazingStuff;
};
awesomeFunction.name;
// "awesomeFunction"
anonymous function
.You can also have a named function expression:
var awesomeFunction = function someName(coolThings) {
// ..
return amazingStuff;
};
awesomeFunction.name;
// "someName"
awesomeFunction
doesn't happen until runtime.// generator function declaration
function *two() { .. }
// async function declaration
async function three() { .. }
// async generator function declaration
async function *four() { .. }
// named function export declaration (ES6 modules)
export function five() { .. }
// IIFE
(function(){ .. })();
(function namedIIFE(){ .. })();
// asynchronous IIFE
(async function(){ .. })();
(async function namedAIIFE(){ .. })();
// arrow function expressions
var f;
f = () => 42;
f = x => x * 2;
f = (x) => x * 2;
f = (x,y) => x * y;
f = x => ({ x: x * 2 });
f = x => { return x * 2; };
f = async x => {
var y = await doSomethingAsync(x);
return y * 2;
};
someOperation( x => x * 2 );
//
class SomethingKindaGreat {
// class methods
coolMethod() { .. } // no commas!
boringMethod() { .. }
}
var EntirelyDifferent = {
// object methods
coolMethod() { .. }, // commas!
boringMethod() { .. },
// (anonymous) function expression property
oldSchool: function() { .. }
};
Since the Boolean(..)
function always returns a value of type boolean, the ==
vs ===
in this snippet is irrelevant; they'll both do the same thing.
var x = "hello";
if (Boolean(x) == true) {
// will run
}
// which is the same as:
if (Boolean(x) === true) {
// will run
}
A prototypal class with Object.create(..)
var Classroom = {
welcome() {
console.log("Welcome, students!");
}
};
var mathClass = Object.create(Classroom);
mathClass.welcome();
// Welcome, students!
All functions by default reference an empty object at a property named prototype
.
This is not the function's prototype (where the function is prototype linked to), but rather the prototype object to link to when other objects are created by calling the function with new
.
So you could do this instead:
function Classroom() {
// ..
}
Classroom.prototype.welcome = function hello() {
console.log("Welcome, students!");
};
var mathClass = new Classroom();
mathClass.welcome();
// Welcome, students!
class Classroom {
constructor() {
// ..
}
welcome() {
console.log("Welcome, students!");
}
}
var mathClass = new Classroom();
mathClass.welcome();
// Welcome, students!
So, in a nutshell:
🤔 What is the lexical scope mechanism of JavaScript?
🤔 What are the two ways of interacting with a variable?
🤔 What is the TDZ (temporal dead zone) error?
const
: because if const
was initialized as undefined
(when hoisted), and then again changed to its intended value, that would be a type change (which const
doesn't allow!).🤔 What is shadowing?
When you have two variables at different scopes, have the same name.
🤔 What is an auto-global?
Dynamically creating variables on the global scope (during run time, not compile time) - this is something you should avoid doing! This can't be done if you have strict mode
enabled (you would get a ReferenceError
).
🤔 What is the difference between undefined and undeclared?
🤔 What is the principle of the least privilege?
It suggests that you should default everything to private and only expose the minimal necessary. It's one of the core CS principles and a defensive approach.
This helps us avoid the following problems:
🤔 Why does an IIFE do?
let
and const
hoist to a block, var
hoists to a functionvar
variables are initialized as undefined
(so both defined and initialized)let
&const
are only defined🤔 Why can't function expression be hoisted?
(more in latter chapters)
Falsy values:
0
, -0
null
Nan
false
undefined
You are already doing coercion whenever you put a value that is not a string inside string literals (${}
)!
If you want to be explicit about it you could do:${String(numValue)}
+ operator
if either of the values is a string, +
prefers to do concatenation (instead of addition)
The ""root of all evil in JS"":
Number("")
0
🤔 What is Boxing?
next()
.boolean
that is false until the iteration over the underlying data source is complete.next()
call for done to be true
to stop the iteration.for ... of
loopsvar vals = [ ...it ];
doSomethingUseful( ...it );
🤔 ...
acts both as a spread operator and a rest parameter?
function add(...args) {
let result = 0;
for (let arg of args) result += arg;
return result
}
const arr = ["Joy", "Wangari", "Warugu"];
const newArr = ["joykare", ...arr];
🤔 Why is map
not considered a default consuming iterator?
map
, the iteration is not just over the map's values but instead its entries.🤔 What is a Map()
constructor?
new Map([iterable])
let myMap = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
])
an iterable is a value that can be iterated over
iterables can be strings, arrays, maps, sets, and others.
For the most part, all built-in iterables in JS have three iterator forms available: keys-only keys()
, values-only values()
, and entries entries()
.
Keys are the property names inside of an object.
Values are property values associated with property names.
Entries are the (key-value) pairs of property names and their values.
🤓 Aaaaand another definition:
this
keywordthis
is not a fixed characteristic of a function based on the function's definition, but rather a dynamic characteristic that's determined each time the function is called (aka depending on the execution context)this
is not determined by the function definition, but rather by how the function was invoked (aka executed aka ()
).this
-aware function can have a different context each time it's called - which makes it more flexible and reusable🤔 What is an execution context?
🤓 More resources! Understanding the this
keyword explanation by Gordon Zhu
🤔 What are the four different ways of invoking a function?
call
, apply
, bind
methodsnew
keyword: the this
keyword will point at a brand new empty object🤯 Arrow functions do not define their own this
keyword, which means that if this
is used inside an arrow function, it will lexically resolve to some enclosing scope that does define the this
keyword (which is the behavior you might want!)
But arrow functions do still have their lexical scope!
🤯 Just because objects use curly braces doesn't mean that they define a new scope, which means that the object's properties aren't lexically scoped.
this
is a characteristic of function execution, a prototype
is a characteristic of an object, and specifically resolution of property access.new
).🤔 What is dunder prototype?
Object.prototype
.Object.create(..)
utility.Object.create(null)
creates an object that is not prototype-linked anywhere, so it's purely just a standalone object; in some circumstances, that may be preferable.this
will remain the same this
from the call site.JS treats files like programs, meaning if one fails (during parse/compile or execution), that will not necessarily prevent the following file from being processed.
💡 But! Many projects use build process tools that combine separate files from the project into a single file to be delivered to a web page. When this happens, JS treats this single combined file as the entire program.
🤔 What is a module?
A module is a collection of state and publicly exposed methods to operate on that state.
A type is a set of intrinsic characteristics that we expect to do with that value.
string
number
boolean
symbol
(used as special keys on objects, mostly used in low-level code such as in libraries and frameworks)null
undefined
(the default value, does not currently have a value)The last two indicate emptiness (or absence) of a value.
array
: a special type of object that's comprised of an ordered and numerically indexed list of data 👍
JS arrays can hold any value type, either primitives or an object.
function
: like arrays, are a special kind (aka, sub-type) of object
.
object
: an unordered, keyed collection of any various values
with objects you access the element by a string location name (aka "key" or "property") rather than by its numeric position (as with arrays)
- typeof 42; // "number"
- typeof "abc"; // "string"
- typeof true; // "boolean"
- typeof undefined; // "undefined"
- typeof null; // "object" 😱
- typeof { "a": 1 }; // "object"
- typeof [1,2,3]; // "object" (should be array?) 😱
- typeof function hello(){}; // "function" 😱
let
allows for block scoping, and signals a local usage of a variablevar
for declaring variables that will be seen by a wider scope (aka not block scoped)const
must be given a value when it's declared and cannot be reassigned to a different value later.const
declared variables are not "unchangeable". They just cannot be reassigned (you can still change values inside objects and arrays, but you can't reassign a different type to that variable) - Note to self: changing an objects is not reassigning a type init?const
only with primitive values, you avoid any confusion of re-assignment (not allowed) vs. mutation (allowed)!🤔 What is block scoping?
let
or const
declared inside of them 🤯awesomeFunction
and the function value here, happens during the compile phase of the code before that code is executed.function awesomeFunction(coolThings) {
// ..
return amazingStuff;
}
var awesomeFunction = function(coolThings) {
// ..
return amazingStuff;
};
🤔 Once again for the folks sitting at the back, what is the difference between a function expression and function declaration?
object
value typereturn
keyword===
operator.===
disallows any type of conversion (aka, "coercion") in its comparison, where other JS comparisons do allow coercion.==
and ===
are exactly the same when the types match 🤯😰 Edge cases
NaN === NaN; // false use Number.isNaN(..) instead
0 === -0; // true use Object.is(..)
💡 But this is useful! null == undefined
- aka empty value - meaning you can check for null
, and this will automatically encompass the undefined
checks as well.
NaN
not a number, you should think of it as an invalid number.Nan
is the only value without the identity property (it's not equal to itself)isNan ()
coerces values to numbers before checking if they are Nan
, that's why we use Number.isNan()
instead 👍Object.is(..)
as the "quadruple-equals" ====
, the really-really-strict comparison!var x = [ 1, 2, 3 ];
// assignment is by reference-copy, so
// y references the *same* array as x,
// not another copy of it.
var y = x;
y === x; // true
y === [ 1, 2, 3 ]; // false
x === [ 1, 2, 3 ]; // false
==
and ===
do exactly the same thing, no difference whatsoever.==
differs from ===
in that it allows coercion before the comparison.==
tends to reduce everything to numbers (ToNumber()
) to make the comparison==
only compares primitives. If one of the values isn't primitive, it will run a ToPrimitive
on it==
is not about comparisons with unknown types!🤔 When should you avoid using ==
?
==
with 0 or ""
(or even " "
)==
with non-primitives==
true or ==
false: allow ToBoolean
or use ===
👍 Use ==
when you know the types, and use ===
when you don't know the types.
new
keywordnew
are: Object()
, Array()
, Function()
, Date()
, RegExp()
, Error()
- but NOT! String()
, Number()
, Boolean()
🤔 What is polymorphism?
The fact that both the inherited and overridden methods can have the same name and co-exist.
The key hallmarks of a classic module are an outer function (that runs at least once), which returns an "instance" of the module with one or more functions exposed that can operate on the module instance's internal (hidden) data.
The class form stores methods and data on an object instance, which must be accessed with the this. prefix
. With modules, the methods and data are accessed as identifier variables in scope, without any this. prefix
.
With class, the "API" of an instance is implicit in the class definition—also, all data and methods are public. With the module factory function, you explicitly create and return an object with any publicly exposed methods, and any data or other unreferenced methods remain private inside the factory function.
ES modules (ESM), introduced to the JS language in ES6, are meant to serve much the same spirit and purpose as the existing classic modules
First, there's no wrapping function to define a module. The wrapping context is a file. ESMs are always file-based; one file, one module.
Second, you don't interact with a module's "API" explicitly but rather use the export keyword to add a variable or method to its public API definition. If something is defined in a module but not exported, then it stays hidden (just as with classic modules).
you don't "instantiate" an ES module. You just import it to use its single instance (there's only one instance ever created, at first import in your program, and all other imports receive a reference to that same single instance)
If your module needs to support multiple instantiations, you have to provide a classic module-style factory function on your ESM definition for that purpose.
🔗 More on modules: Unbundling the JavaScript module bundler by Luciano Mammino
]]>Since January 1. of this year (2021), my wife and I have switched to (almost) exclusively speaking Spanish at home. My plan is to become some sort of fluent by the end of June (2021). Fortunately, Valerie, my Mrs, is on board and has agreed to help me.
I'm not a native Spanish speaker (Valerie is), nor have I had any formal Spanish training. But enough is enough, we've been together for almost ten years, and I find it almost embarrassing that I haven't learned it yet. Also, we currently speak English to each other, which is just odd since neither of us is a native English speaker.
And for the added bonus, we are also stuck at home with no exciting plans of leaving the house much, so... might as well?
I suppose I'm ( used to be 😭) alright when it comes to learning foreign languages. I speak Slovenian (my native language), have a BA in English and another one in Mandarin Chinese. I've lived in China for five years, picked up some Japanese on the way, and was at some points able to understand Tsingtao beer-fuelled Russian screamed at me at the wee hours of the morning... Oh, how I don't miss my student days...
I also worked as a teacher and translator for a while; I was part of a two-person Chinese learning podcasting empire (hah!), but then life (ahem bills) got in the way, and I decided to look for a slightly more stable and less stressful career. Thus I landed in programming.
Blah. Okay, that's done.
Disclaimer: I should first say that before this, my Spanish could be described as super elementary. I did do a bunch of Duolingo way back when that didn't stick. I also picked up some from listening to Valerie talk to her family, some from watching movies or series, some from randomly studying.
Before starting all of this, I would describe my Spanish level as:
Every day for the past 60 days, without exception, I've done the following three things:
I really like Language Transfer and usually do 20-30min of listening to that while doing the dishes etc. It's great for learning grammar and making connections between languages. I'm currently doing it the second time around.
Most importantly, as much as I can, I try talking to Valerie exclusively in Spanish (or at least, my take on Spanish). We tend to pause this during stressful working hours (because it just takes too much brainpower) and when I really excitedly want to tell her something (for example the kitchen is on fire!).
This has gone... surprisingly well (my opinion 😬). I mean, it's been really difficult, and I sound very... basic and make 90 mistakes/minute, but because Valerie is an 👼 (but grown-up) in disguise, it's at least less horrible than it used to be (again, my opinion).
I can comfortably express myself in the present, past, and future tenses but regularly mess up irregular verbs and everything else that isn't straightforward (conditionals, subjunctive, commands, past perfect (past in the past))... I got all of our most common phrases nailed, and I can say: "Did you bring a doggie poo bag?" (we do have a dog) in my sleep.
My vocabulary is alright, my listening skills are improving, and my pronunciation is decent.
Besides the three regulars, there's also the miscellaneous bucket of consuming content that I like, but in Spanish, that includes:
Thanks to Valerie, we have lots of Spanish books, and I can't understand any of them. I've now started reading Agatha Christie's novels in Spanish, it's still super difficult, but at least I already know the genre 😳.
My favorites are Jesse & Joy, La Oreja de Van Gogh, Los Auténticos Decadentes, Lila Downs and Café Tacuba. Also, Nortec Collective, but that's instrumental, so I guess that doesn't count 😆.
Lots of Radio Ambulante, which features content from all over the Spanish-speaking world, so you get to really practice those accents (or, in my case, get frustrated because you can't understand any of the accents!).
We tend to liten to Spanish radio during our lunch breaks. So far I've tried RTVE and Cadena SER. Spaniards talk so fast! 😱
I changed my phone's language to Spanish! And now, every time I see "Tienes más mensajes Nuevos" pop up on my phone, I get to read it (in my head) in a dramatic Spanish accent (think Antonio Banderas).
El Secreto de Sus Ojos being my favorite, but I also enjoyed the telenovela Mirada de Mujer featuring a romance between a 50 something lady and a 35 something man (woooohooo Mexico!).
Also, Almodovar (Dolor y Gloria!), the documentary Midnight Family is really really good (about a family-run private ambulance. Yes, that's a thing in Mexico!). If possible, with Spanish subtitles. If no subtitles, pretend to understand stuff and laugh at the same time wife does.
I pick some up from Language Transfer, and I have two grammar books that I sometimes peek at. Otherwise, pester Valerie.
I try to talk to myself in Spanish. This normally results in both of us getting confused.
So, how comfortable am I today, 1/3 into my learning journey, that I'll be able to achieve Spanish fluency by the end of June?
After having done 60 days of studying around 2 hours each day, I would describe my Spanish level as:
There are days (like today) when everything I say is wrong or mumbled, or just complete nonsense, and I feel I'll never get it. And it's tiring hearing yourself (poor Valerie ❤️) making the same mistakes over and over again, or saying things like Me no want salad, me want potato". Sigh.
But then again, there are better days. When we have pizza.
In any case, I'll keep you posted.
]]>🤔 What is a global execution context?
There is one global execution context, but you can have multiple function contexts.
🤔 What is the JS thread like?
🤔 What happens when you execute a function?
You create a new execution context!
🤔 What is a call stack?
It's a special data structure that allows us to track where the thread of execution is (whatever is on top of the call stack) and where to return to after an execution context is popped off the stack.
A stack is a structure where the last thing you put into it is the first thing that you take ou: push/pop).
🤔 What are some of the core features of functional programming?
return
value🤔 What do we mean by functions are first-class objects?
They can co-exist with and can be treated like any other JavaScript objects.
But! Unlike objects, functions can be run aka evoked with ()
.
🤔 What is a higher-order function?
🤔 What is a callback?
🤔 What is an identifier?
What follows is a long explanation of what closures are and how they work (and should they be called closures?):
👍 Where you define your functions determines what variables your function have access to when you call the function.
When a function is defined, it gets (an invisible) [[scope]]
property that references the Local Memory/Variable Environment in which it has been defined.
When calling a function, JS will always look first in its immediate local memory (variable environment), and then in the [[scope]]
property next before it looks any further up
Our lexical scope (the available live data when our function was defined) is what determines our available variables and prioritization at function execution, not where our function is called.
Asynchronicity is the backbone of modern web development in JavaScript.
JavaScript is single-threaded (one command executing at a time) and has an asynchronous execution model (each line is executed in order the code appears).
🤔 But, What if we need to wait sometime before we can execute certain bits of code? How do we delay some code execution but avoid blocking the thread from any further code running while we wait?
Answer!
And so we add three new pieces (original 3: thread of execution, memory/variable environment, call stack):
👍 The stuff from the callback queue (meaning coming from the browser API) won't get added to JS's call stack until the call stack is empty.
setTimeout
tells you for how long, at the minimum, you will delay the execution for.🤔 What are the rules for executing asynchronously delayed code?
🤔 What is an event loop?
🤔 When would you use Browser API (to avoid blocking the JS thread)?
🤔 What are some of the benefits of OOP?
🤔 What are the different ways of declaring an object?
{}
and add stuff with dot-notationObject.create()
__proto__
)function userCreator(name, score) {
// we are creating an empty object and assigning it's `__proto__` property to userFunctionStore
// basically making userFunctionStore the parent object
let newUser = Object.create(userFunctionStore);
newUser.name = name;
newUser.score = score;
return newUser;
};
let userFunctionStore = {
increment: function() {
this.score++;
},
login: function() {
console.log("You're loggedin");
}
};
let user1 = userCreator("Will", 3);
user1.increment();
new
(which automates the chaining for us!)let user1 = new userCreator("Will", 3
When we call the constructor function with new in front, we automate two things:
function userCreator(name, score) {
let newUser = Object.create(functionStore);
newUser this.name = name;
newUser this.score = score;
return newUser;
};
functionStore userCreator.prototype // {};
functionStore userCreator.prototype.increment = function() {
this.score++;
}
let user1 = new userCreator("Will", 3);
🤯 Functions are just objects that can be run (have some extra functionality bits)!
// aka a constructor function
function User(name, score) {
// with new `this` becomes {}
this.name = name;
this.score = score;
}
User.prototype.increment = function() {
this.score++;
};
User.prototype.login = function() {
console.log("login");
};
let user1 = new User(“Eva”, 9) user1.increment();
// `__proto__` becomes User.prototype
class User {
constructor(name, score) {
this.name = name;
this.score = score;
}
increment() {
this.score++;
}
login() {
console.log("login");
}
}
let user1 = new User("Eva", 9);
user1.increment();
]]>🤔 What is the difference between a script and a program?
Also:
The JavaScript/JS that runs in your browser or in Node.js
, is an implementation of the ES2019 standard.
TC39 is the technical steering committee that manages JS. Their primary task is managing the official specification for the language. They meet regularly to vote on any agreed changes, which they then submit to ECMA, the standards organization.
All proposals are managed in the open, on TC39's Github repository.
For the most part, the JS defined in the specification and the JS that runs in browser-based JS engines is the same. But there are some differences that must be considered.
Sometimes the JS engines will refuse to conform to a specification-dictated change because it would break that web content.
In these cases, often TC39 will backtrack and simply choose to conform the specification to the reality of the web.
Various JS environments (like browser JS engines, Node.js
, etc.) add APIs into the global scope of your JS programs that give you environment-specific capabilities, like being able to pop an alert-style box in the user's browser.
So alert(..)
and console.log(..)
are not defined by JS. They are functions and object methods, and they obey JS syntax rules. The behaviors behind them are controlled by the environment running the JS engine, but on the surface, they definitely have to abide by JS to be able to play in the JS playground.
The developer console is not trying to pretend to be a JS compiler that handles your entered code exactly the same way the JS engine handles a .js
file.
🤔 What is a Browser API?
🤔 What is a (programming) paradigm?
A mindset and approach to structuring code
Typical paradigm-level code categories include:
Multiparadigm languages (like JavaScript) can mix and match from different paradigms.
🤔 What is backwards compatibility?
🤔 What is forwards compatibility?
HTML and CSS, by contrast, are forwards-compatible but not backwards-compatible.
🤔 What is transpiling?
🤔 What is a polyfill? (aka Shim?)
Scripting and interpreted languages have historically been looked down because of lack of performance optimization, as well as dislike of certain language characteristics, such as scripting languages generally using dynamic typing instead of the "more mature" statically typed languages.
Languages regarded as "compiled" usually produce a portable (binary) representation of the program that is distributed for execution later (which potentially disqualified JS).
Historically, scripted or interpreted languages were executed in generally a top-down and line-by-line fashion.
Compiled languages go through: Parsing + Compilation + Execution
All compiled languages are parsed.
Translation from the parsed form of the program to its executable form is usually called an Abstract Syntax Tree (AST).
JS source code is parsed before it is executed (it throws static errors, before it's executed).
The parsed JS is converted to an optimized (binary) form, and that "code" is subsequently executed.
🤔 What is compilation?
🤔 What is Just in Time Compilation?
🤔 What happens during compilation?
keys
to (list) elementsid
)When can you use index
(instead of id
's):
🤔 What is memoization? In computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.
React.memo
only checks for prop changes. If your function component wrapped in React.memo
has a useState
or useContext
Hook in its implementation, it will still re-render when state or context change.React.memo()
does a shallow comparison of props and objects of props.When to use it?
👍 When you expect the functional component to render often and usually with the same props
react-window
, react-virtualized
Netlify:
yarn build
) or import from GitHub (the build
scripts will be pre-filled)Vercel:
yarn global add vercel
vercel login
vercel
Netlify:
Next
is a server-side rendered app and Netlify only supports static sites. In other words, Netlify needs an HTML file to be able to host your website.next export
to build the appbuild
config: Build Command: next build && next export
, Publish directory: out
package.json
: "build:static": "next build && next export"
Vercel:
vercel.
useEffect
will always render on mount unless told otherwise because all props get changed on mount🤔 What is a Race Condition Bug?
A race condition can happen when there are two asynchronous processes that will both be updating the same value.
Effect callbacks are synchronous to prevent race conditions, so you can not make it async but can call async functions from it by appending a then to it
This is kosher:
useEffect(() => {
getCharacter(openId).then((rsp) => setInfo(rsp));
}, [openId]);
async
function (cancel a promise):function BananaComponent() {
const [bananas, setBananas] = useState([])
useEffect(() => {
let isSubscribed = true
fetchBananas().then( bananas => {
if (isSubscribed) {
setBananas(bananas)
}
})
return () => isSubscribed = false
}, []);
useEffect
runs asynchronously and after a render is painted to the screen.Meaning:
useLayoutEffect
, on the other hand, runs synchronously after a render but before the screen is updated.
Meaning:
You cause a render somehow (change state, or the parent re-renders)
React renders your component (calls it)
useLayoutEffect runs, and React waits for it to finish.
The screen is visually updated
99% of the time, useEffect.
const increment = () => {
setCount(counter + 1);
setCount(counter + 1);
setCount(counter + 1);
};
Reason: React will batch them up, figure out the result, and then efficiently make that change.
When dealing with updating the state depending on its current value, we should access it like so (this will increment it by three):
setCounter((counter) => counter + 1);
setCounter((counter) => counter + 1);
setCounter((counter) => counter + 1);
useContext
lets you subscribe to React context without introducing nestinguseReducer
lets you manage the local state of complex components with a reducer:function reducer(state, action) {
switch (action.type) {
case "removeVisited":
return state;
case "addVisited":
return state;
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, {
airports: airportList,
});
dispatch({ type: "removeVisited", value: airport.id });
current
propertyuseMemo
memoizes a value, useCallback memoizes a functionuseCallback
: give me the previously created function unless any of the dependencies I send you changeuseCallback
gives you referential equality between renders for functions. And useMemo
gives you referential equality between renders for values.useCallback
returns its function when the dependencies change, while useMemo
calls its function and returns the result.function foo() {
return "bar";
}
const memoizedCallback = useCallback(foo, []);
const memoizedResult = useMemo(foo, []);
memoizedCallback;
// ƒ foo() {
// return 'bar';
// }
memoizedResult; // 'bar'
memoizedCallback(); // 'bar'
memoizedResult(); // 🔴 TypeError
]]>Is a tool to document and test your components in isolation.
👍 There's a ready-made create-react-app
storybook integration and a storybook CLI
.
Create a .storybook/main.js
in the root of the project` and a stories file.
For adding the CRA preset (inside main.js
):
module.exports = {
addons: ["@storybook/preset-create-react-app"],
stories: ["../src/**/*.stories.js"],
};
stories.js
in one of the components folders, and we will already see something.e.g.:
import React from "react";
import Button from "./";
export default {
title: "components/Button",
component: Button,
};
export const basic = () => <Button>Hello Button</Button>;
Storybook comes with a bunch of add-ons:
@storybook/theming
import { addons } from "@storybook/addons";
import { themes } from "@storybook/theming";
addons.setConfig({
theme: themes.dark,
});
addon-actions
: add-on to trigger actions (onClick
etc) on our form components, like our buttons.
addon-knob
: allows you to interact with your components and change their properties in real-time
addon-a11y
: to test the accessibility of our components
Further links: Emma Bostian's FrontEnd Masters workshop notes
🤔 vs. REST API
POST
request. It does not need a resource URL + verb combo.query {
totalPets
}
JSON
object.hit ctrl + space
for a list of available queries
hover over a field and press command - which will link to the schema
use the Query Variable panel to pass in variables
you can send tokens through the HTTP Headers panel
The schema defines:
Further links: Scott Moss' FrontEnd Masters workshop
🤔 What is apollo? It' a bunch of tooling around GraphQL that encapsulates HTTP logic used to interact with a GraphQL API. It doubles as a client-side state management alternative as well (you can use GraphQL for querying local state). Framework independent. Provides extra features if you also use Apollo Server.
🤔 The real power of GraphQL is connecting different data points.
If you have more than one (unnamed) query - you have to name them.
Queries are used to request specific data from the endpoint.
Mutations are another type of GraphQL operation that are similar to queries, but they are used when you need to change any data on the backend.
Fragments are selection sets that can be used across multiple queries. They allow you to refactor redundant selection sets, and they are essential when querying unions or interface types.
Interfaces are similar to Unions in that they provide a mechanism for dealing with different types of data.
Unions are used when we want a GraphQL field or list to handle multiple types of data.
A GraphQL API can push new data to the client with the Subscription Type.
date-fns
react-icons
Reakit
Chakra UI
history
: The history library lets you efficiently manage session history anywhere JavaScript runs (it's now a peer dependency)
<Route path="/" element={<Home />}/>
== <Home path="/" />
<Link>
To create links between pages in the same app.
The <Switch/>
component has been replaced by <Routes/>
in version 6.
React router version 6 replaces the useHistory()
hook with the useNavigate()
hook.
Params are placeholders in the URL that begin with a colon, like the :id
param defined in the route in this example.
Nested routing helps us to render the sub-routes like users/1
, users/2
, etc.
Use Outlet
to tell the parent that it has to render any of the matching children that it finds.
NavLink
: a special type of Link component that knows when it's active and accepts an activeStyle
or an activeClassName
that will be activated when you are in the route the link points to.
import { createOvermind } from "overmind";
import { createHook, Provider } from "overmind-react";
To animate an element, you make it a motion element (motion.h1
, motion.p
...), then give it an animate
prop with value as an object.
Some other properties: initial
, transition
, whileHover
,exit.
Also, variants
! (for abstracting properties)
Solve the issue of string interpolation, theming, SSR, and even global styles that are attached to the theme.
For keeping your presentational components separate from the logic.
Every styled component will know about the styling from the ThemeProvider
!
import { ThemeProvider } from "styled-components";
import { theme } from "./utils/styles"; // where we define our styles
<ThemeProvider theme={theme}>
export const Style = createGlobalStyle`
body {
text-align: center;
margin: 0;
background-color: ${(props) => props.theme.colors.black};
color: ${(props) => props.theme.colors.white};
font-family: ${(props) => props.theme.font}
} `;
styled
function (don't forget to add the backticks!)const Heading = styled.h1`
display: block;
`;
background: ${({ theme, react }) => (react ?
theme.colors.white : "black")};
import { useFormik } from "formik";
We pass our form's initialValues
and a submission function (onSubmit
) to the useFormik()
hook.
We also get a bunch of helper methods:
handleSubmit
: A submission handlerhandleChange
: A change handler to pass to each <input>
, <select>
, or <textarea>
values
: Our form's current valuesFormik
keeps track of not only your form's values but also its error messages and validation.
Given some field-level info, it returns the exact group of onChange
, onBlur
, value
, checked
for a given field. You can then spread that on an input
, select
, or textarea.
from:
<input
onChange={formik.handleChange}
value={values.email}
onBlur={formik.handleBlur}
type="email"
id="email"
/>
<input {...getFieldProps("email")} type="email" id="email" />
Yup
validation library (from the Joi
family)🟢 Pros:
🔴 Cons:
eject
)🤔 What is server-side rendering?
🤔 Server-side- vs client-side rendering?
SSR means you run javascript on your server and render the app to HTML before sending it to the client. Just like a traditional web server would, except you also send the raw data required to render the page and use that to "hydrate" your application on the client.
CSR means you forego all that, use whatever for your server, and just let the browser render the page. Since the HTML response body from the server will then be practically nothing but an empty HTML structure with a script tag, crawlers that don't run javascript will have no idea what's going on on your page.
More here
🟢 Pros:
.babelrc
)npx create-next-app
)🔴 Cons:
a steep learning curve, mostly because SSR things are just harder
harder to leave if Next is not the best tool for your project
🟢 Pros:
npx gatsby new gatsby-site.
🔴 Cons:
🤔 What are the benefits of static sites?
🤔 How do Gatsby and Next compare?
for many use cases where you need state spread around your application (but the state is not too complex)
Context
: provides us with two components: a Provider
and a Consumer
.
Provider
: holds the values
Consumer
: reads the values (via useContext
hook)
🕵️♀️ Example:
import React, { useContext } from "react";
const Person = {
name: "Sara",
city: "Berlin",
nationality: "Portugal",
};
const PersonContext = React.createContext();
const Header = () => {
const person = useContext(PersonContext);
return <p>Hello {person.name}</p>;
};
const Main = () => {
const person = useContext(PersonContext);
return (
<p>
I see with you are from {person.nationality} and live in {person.city}
</p>
);
};
const App = () => {
return (
<PersonContext.Provider value={Person}>
<>
<Header />
<Main />
</>
</PersonContext.Provider>
);
};
export default App;
To be discussed later in a separate chapter
]]>In general, bash scripts are useful for short and simple one-off scripts when you just want to run a specific series of commands. For larger and/or more complex scripts use a more mature scripting languages like Python or Ruby (bash scripts can easily become overly complicated and unreadable).
But also (for bash vs Python):
In both cases, the script.sh
will be read and executed in a bash session, the difference lies in which session is running the commands.
source script.sh
command are executed in current bash session, so any changes made in the current environment (such like changing directories or defining functions, all variable assignments) will persist.
./script
will run a new instance of bash, the variables aren't preserved.
In general, there are some conventions about where specific types of files live.
/bin
- Essential command binaries/sbin
- Essential system binaries, usually to be run by root/dev
- Device files, special files that often are interfaces to hardware devices/etc
- Host-specific system-wide configuration files/home
- Home directories for users in the system/lib
- Common libraries for system programs/opt
- Optional application software/sys
- Contains information and configuration for the system (covered in the first lecture)/tmp
- Temporary files (also /var/tmp). Usually deleted between reboots./usr/
- Read only user data
/usr/bin
- Non-essential command binaries/usr/sbin
- Non-essential system binaries, usually to be run by root/usr/local/bin
- Binaries for user compiled programs/var
- Variable files like logs or cachesA virtual machine is a system that acts exactly like a computer.Each virtual machine requires its underlying operating system, and then the hardware is virtualized.
Docker is a tool that uses containers to make the creation, deployment, and running of applications a lot easier. It binds the application and its dependencies inside a container.
The main difference between containers and virtual machines is that virtual machines will execute an entire OS stack, including the kernel, even if the kernel is the same as the host machine.
Unlike VMs, containers avoid running another instance of the kernel and instead share the kernel with the host.
VM | Docker |
---|---|
Hardware-level process isolation | OS level process isolation |
Each VM has a separate OS | Each container can share OS |
Boots in minutes | Boots in seconds |
VMs are of few GBs | Containers are lightweight (KBs/MBs) |
Ready-made VMs are difficult to find | Pre-built docker containers are easily available |
VMs can move to new host easily | Containers are destroyed and re-created rather than moving |
Creating VM takes a relatively longer time | Containers can be created in seconds |
More resource usage | Less resource usage |
The table is courtesy of Geekflare
]]>✏️ Four main folders (inside src
):
components
pages
assets
utils
For state management
context
👩💻 Compared to how we have it set up at work:
components
✅ (Button
also lives here)pages
✅ (we straight up call them screens
)utils
We don't have a separate assets folder. 🤔
But we have (in addition):
modules
for state management (Redux
and hooks
)API
for talking to the backendlegacy
shame 😊😱 What is Overmind? (to be revealed in a future chapter)
✏️ "I always try to name my files index.js
and let the folder name do the talking."
👩💻 (I currently give each file a specific name.)
But, but, what happens when you're searching?
✏️
const LandingPage = () => {};
export default LandingPage;
👩💻
export default function LandingPage() {}
eslint-config-react-app
😱 But to add to a project (outisde of create-react-app
):
npm install --save-dev eslint-config-react-app @typescript-eslint/eslint-plugin@^4.0.0 @typescript-eslint/parser@^4.0.0 babel-eslint@^10.0.0 eslint@^7.5.0 eslint-plugin-flowtype@^5.2.0 eslint-plugin-import@^2.22.0 eslint-plugin-jsx-a11y@^6.3.1 eslint-plugin-react@^7.20.3 eslint-plugin-react-hooks@^4.0.8
🤔 Besides typesettings, what else does TypeScript give you?
🤔 Proptypes vs typescript?
Typescript and PropTypes serve different purposes. Typescript validates types at compile-time, whereas PropTypes are checked at runtime.
Typescript is useful when you are writing code: it will warn you if you pass an argument of the wrong type to your React components, give you autocomplete for function calls, etc.
PropTypes are useful when you test how the components interact with external data.
🤔 Compile-time vs runtime?
Source code (if written in a high-level programming language) must be compiled into machine code to be an executable program. The operations at compile time include syntax analysis, semantic analysis, and code generation. During compilation, errors can occur. They occur due to syntax and semantic errors.
The runtime is also known as execution time. It is the time when a program is running in contrast to other program lifecycle phases such as compile-time, load time, etc.
When the compilation process is completed, it is run by the user. The time period to run the executable generated at compile time is referred to as runtime. Runtime errors are known as exceptions.
This usually involves some software that is listening and, whenever a certain key is pressed, it intercepts that event and replaces it with another event corresponding to a different key.
Further links for Karabiner (macOS) config:
👍 It's recommended to use goku
(and the .edn
format) for the Karabiner config file instead of .json
format, which is super bloated.
My current remappings:
CapsLock
-> another modifiter keyShift
+ CapsLock
-> Caps LockRight Shift
+ w
/a
/s
/d
-> right-side arrow keysCapsLock
+ f
-> full-screen everythingCapsLock
+ t
-> open terminalDaemons are processes that are often started when the system is bootstrapped and terminate only when the system is shut down. Because they don’t have a controlling terminal, they run in the background. The programs that run as daemons often end with a d
to indicate so.
For example, sshd
, the SSH daemon, is the program responsible for listening to incoming SSH requests and checking that the remote user has the necessary credentials to log in.
🤔 What is the difference between daemons and launch agents?
Daemons are system-wide services that always run in the background, while agents describe regular services that are to be executed on user-specific events.
🤔 Where can I find launch daemons and agents?
~/Library/LaunchAgents
/Library/LaunchAgents
/Library/LaunchDaemons
/System/Library/LaunchAgents
/System/Library/LaunchDaemons
Filesystem in Userspace (FUSE) is a software interface for Unix and Unix-like computer operating systems that lets non-privileged users create their own file systems without editing kernel code. This is achieved by running file system code in user space while the FUSE module provides only a "bridge" to the actual kernel interfaces.
FUSE is useful especially for writing Virtual file systems where you don't store/retrieve data from an actual disk.
Examples:
GmailFS
: filesystem which stores data as mail in GmailWikipediaFS
: View and edit Wikipedia articles as if they were real files👍
--help
flag to display brief usage instructions for the tool.--dry-run
which only prints what the command would do but does not actually perform the change.-i
for “interactive” (especially for destructive actions)--version
or -V
for program version.--verbose
or -v
flag to produce more verbose output. -vvv
for even more verbose output--quiet
flag for making it only print something on error.-
in place of a file name means “standard input” or “standard output”, depending on the argument.-r
for recursive--
makes a program stop processing flags and options (things starting with -) in what follows, letting you pass things that look like flags without them being interpreted as such: rm -- -r or ssh machine --for-ssh -- foo --for-foo.
Rectangle (similar to RIP Spectacle) vs Magnet vs others
👍
👍
Hammerspoon is a desktop automation framework for macOS. It lets you write Lua scripts that hook into operating system functionality, allowing you to interact with the keyboard/mouse, windows, displays, filesystem, and much more.
Live USBs are USB flash drives containing an operating system.
Virtual machines and similar tools like containers, let you emulate a whole computer system, including the operating system.
Vagrant
is a tool that lets you describe machine configurations (operating system, services, packages, etc.) in code, and then instantiate VMs with a simple vagrant up. Docker
is conceptually similar but it uses containers instead.
Like Jupyter, for Python.
👍
]]>Entropy is a measure of randomness.
log2(#possibilities):
Roughly 40 bits is considered a strong password (80 bits for offline attacks and to be really secure).
🤔 What is encryption?
Encryption is a way of using mathematics to scramble the content of a digital file or message so that it can only be decrypted and read by someone who has a particular piece of information, such as a password or an encryption key.
🤔 How to break passwords?
Hash functions are functions that map a variable amount of data (input) into a fixed output.
sha1(bytes) -> 160 bits, typically rendered as a hexadecimal number, 40 digits long. (like in git for content address storage).
SHA-1 is no longer considered a strong cryptographic hash function.
hash(value: array<byte>) -> vector<byte, N>
(for some fixed N)
Hash functions have a number of properties:
🤔 What is a checksum?
A checksum is a sequence of numbers and letters used to check data for errors. If you know the checksum of an original file, you can use a checksum utility to confirm your copy is identical.
Linux distributions often provide checksums so you can verify your Linux ISO properly downloaded before burning it to a disc or putting it on a USB drive.
Typical algorithms used for this include MD5, SHA-1, SHA-256, and SHA-512.
If you want to do a fair coin toss “in my head”, without a trusted shared coin that two parties can see. I could choose a value r = random(), and then share h = sha256(r)
KDFs are similar to hask functions, but on top of that they are (purposefully) slow to compute. Used for password applications (to slow down brute-force attacks)
A key derivation function is an algorithm that generates a cryptographic key from a password or a master key.
🤔 What is a cryptographic key?
A cryptographic key is data that is used to lock or unlock cryptographic functions such as encryption, authentication and authorization. Keys are typically designed to be both random and reasonably long such that they are difficult to guess.
In symmetric-key cryptography (alias secret key cryptography) the same key is used to encrypt and decrypt the data.
keygen() -> key (a randomized function that proudces the key)
encrypt(plaintext: array<byte>, key) -> array<byte> (the ciphertext)
decrypt(ciphertext: array<byte>, key) -> array<byte> (the plaintext aka data)
Meaning that given a ciphertext, you can't figure out the plaintext without the key.
Correctness property: if you decrypt the cipher with a key, it will give you back the original plaintext.
Used for encrypting files for storage on un-encrypted cloud service. They are somewhat less useful for sending messages from one computer to another because both ends of the communication channel must possess the key and must keep it secure
🤔 What is salt?
Salt is/are random data that is added to data before it is passed to a hash function. It is a cryptographic technique that makes hash nodes more difficult to reverse.
A matching public/private key pair whereby anyone can encrypt with the public key, but only those who hold the private key can decrypt.
keygen() -> (public key, private key) (this function is randomized)
encrypt(plaintext: array<byte>, public key) -> array<byte> (the ciphertext)
decrypt(ciphertext: array<byte>, private key) -> array<byte> (the plaintext)
sign(message: array<byte>, private key) -> array<byte> (the signature)
verify(message: array<byte>, signature: array<byte>, public key) -> boolean (whether or not the signature is valid)
When you run ssh-keygen, it generates an asymmetric key pair, public_key, private_key.
🤔 What is PGP?
Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication. Used by ProtonMail
The make utility requires a Makefile
which defines a set of tasks to be executed.
You may have used make to compile a program from source code.
Most open-source projects use make
to compile a final executable binary, which can then be installed using make install
.
Create a makefile
:
say_hello:
echo "Hello World"
And then run it:
$ make
echo "Hello World"
Hello World
Tabs are important!
target: prerequisites
<TAB> recipe
With semantic versioning, every version number is of the form: major.minor.patch:
Lock file: a file that lists the exact version you currently depen on for each dependency.
Vendoring - a.k.a. dependency locking: when you copy all the code of your dependencies into your own project.
Continuous integration, or CI, is an umbrella term for “stuff that runs whenever your code changes” - a.k.a. event-triggered actions. E.g CIs: Travis CI, Azure Pipelines, and GitHub Actions.
They all work in roughly the same way: you add a file to your repository that describes what should happen when various things happen to that repository (e.g. re-run the tests when there are code changes.
Dependabot: checks whether your dependencies are up-to-date and submits an automatic PR if they're not.
The badges in GitHub come from the CI as well: e.g test coverage, dependencies, documentaton versioning.
GitHub pages is a type of a CI action - it builds a blog from your markdown files (using Jeykll).
Which is better because:
🤔 How do you output colors in the terminal? ANSI escape codes are standardized commands used to manipulate the behavior and appearance of the text in a terminal or terminal emulator.
ANSI escape sequence is a sequence of ASCII characters, the first two of which are the ASCII "Escape" and the left-bracket character "[". The character or characters following the escape and left-bracket characters specify an alphanumeric code that controls a keyboard or display function.
The most basic terminals have a set of 8 different colors:
Black: \u001b[30m
Red: \u001b[31m
Green: \u001b[32m
Yellow: \u001b[33m
Blue: \u001b[34m
Magenta: \u001b[35m
Cyan: \u001b[36m
White: \u001b[37m
Reset: \u001b[0m
Example:
print "\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m"
This will print letters A (in black), B (pink), C (green), D (yellow).
var/log/system.log
Or more commonly, the system log (/var/log/system.log
):
log show
🤔 You can also see system logs in:
Finder > Applications > Utilities > Console.
log show --last 10s
Show logs for the past 10 seconds.
logger "hello logs"
Add stuff to the system log (using a shell program called logger
).
log show --last 1m | grep hello
Find that log (the one you just added)
/var/log
/var/log/system.log
/var/log/DiagnosticMessages
/Library/Logs
/Library/Logs/DiagnosticReports
~/Library/Logs
(in other words, /Users/NAME/Library/Logs
)~/Library/Logs/DiagnosticReports
(in other words, /Users/NAME/Library/Logs/DiagnosticReports
)Debuggers are programs that let you interact with the execution of a program and allow you to:
Static analysis programs take source code as input and analyze it using coding rules to reason about its correctness (linters), e.g. shellcheck
for shell scripts, prettier
for HTML, CSS, JS.
Similarly to the debugging case, in many scenarios, it can be enough to just print the time it took your code between two points.
Example:
time curl https://missing.csail.mit.edu &> /dev/null
Will output how long in real, user, and system time it takes to curl
that specific url.
Most of the time, when people refer to profilers, they actually mean CPU profilers.
🤔 Logging vs Tracing vs Monitoring
🤔 Also this Twitter thread.
There's also line profiler, memory profiler, event profiling.
htop
A process viewer.
du -h [path]
List the sizes of a directory and any subdirectories in human-readable form (i.e. auto-selecting the appropriate unit for each size)
lsof
Lists file information about files opened by processes.
lsof path/to/file
Find the processes that have a given file open.
lsof -i :port
Find the process that opened a local internet port.
]]>I also learned a lot from Alex' git workshop
Git models the history of a collection of files and folders within some top-level directory (root directory, the directory in which you do git init
) as a series of snapshots (commits).
🤔 git init creates the .git
directory, which is where Git stores all of its information. If you delete everything except .git
, you can still rebuild your entire repository.
In git folders are trees, and files are blobs.
In pseudocode:
type blob = array<byte>
type tree = map<string, tree | blob>
type commit = struct {
parent: array<commit>
author: string
message: string
snapshot: tree
}
🤔 What do we mean by content-addressable? It means that at the core of Git is a simple key-value data store. This means you can insert any kind of content into a Git repository, for which Git will hand you back a unique key you can use later to retrieve that content. More on git objects from Git Book
🤔 Also, the content of an object determines its ID (two files with the same content will have the same id!). The technical name for this is a content-addressable filesystem.
type object = blob | tree | commit
In Git data store, all objects are content-addressed by their SHA-1 hash:
objects = map<string, object>
def store(object):
// hash-object command
id = sha1(object)
objects[id] = object
def load(id):
return objects[id]
🤔 A typical repo has thousands of objects, so Git breaks up objects into subdirectories to avoid any one directory becoming too large.
🤔 What is a hash function?
A hash function is a function that takes in a big piece of data and turns it into a short string.
Branches and refs are human-readable labels to specific commits. "HEAD" is a reference to where we currently are.
references = map<string, string>
// references are mutable
def update_reference(name, id):
references[name] = id
def read_reference(name):
return references[name]
// cat-file
def load_reference(name_or_id):
if name_or_id in references:
return load(references[name_or_id])
else:
return load(name_or_id)
💡 At a high level, all git command line commands are just manipulations of references data or objects data:
git add
is a combination of hash-object
and update-index
.git commit
comes from write-tree
, commit-tree
, and if you’re on a branch, update-ref
git checkout
uses update-ref
or update-symbolic-ref
If you ls .git
in a new git repository:
HEAD description info refs config hooks objects
The HEAD file tells Git which branch we’re working on
The description file is only used by the GitWeb program – it can be ignored.
The info directory has a single file, exclude, which contains a list of per-repo ignores. Like a gitignore file, but it doesn’t need to be checked in.
The refs directory is empty
The config file contains repo-specific configuration
The hooks directory is used to store scripts that fire on certain events – for example, running a linter before you commit
The objects directory should be empty (aside from two more empty directories)
You'll get the index
file once you've added your changes to the staging area (a.k.a. index)
💡 Staging area is you telling git what changes should be included in the next snapshot.
git cat-file -p [commit sha]
Git's internal command to print out the contents of the commit (used to inspect objects stored in Git). With this command, we can restore our file even if we delete it – because the object is kept safe in the .git
directory:
rm animals.txt`
git cat-file -p b13311e04762c322493e8562e6ce145a899ce570 > animals.txt
git commit -a
To commit all the changes for files that are already tracked - so you can potentially skip git add .
💡 Think of merging as being the opposite of branching.
🤔 git pull
=== git fetch & git merge
git add -p
For interactively deciding what you want to add.
git blame [filename]
To see who made changes to the file.
git show [commit sha]
To see the changes made in the commit.
git bisect
Use binary search to find the commit that introduced a bug.
]]>SIGINT
: Term Interrupt from keyboard (ctrl + c
)
SIGQUIT
: Core Quit from keyboard (ctrl + \
)
SIGHUP
: Terminal line hangup (if you close your terminal, but things - e.g. servers - are still running in the background)
SIGKILL
: Term Kill signal - be vary, can lead to orphan processes
SIGTERM
: Term Termination signal
SIGSTOP
: Stop process ctrl + z
We can then continue the paused job in the foreground or in the background using fg
or bg
.
sleep 20
Put the process to sleep for 20 seconds.
jobs
The jobs command lists the unfinished jobs associated with the current terminal session.
kill
Sends a signal to a process, usually related to stopping the process, e.g. SIGKILL
is kill -9 [pid]
. All signals except for SIGKILL and SIGSTOP can be intercepted by the process to perform a clean exit.
If you add &
to the end of a terminal command, it will start the execution in the background.
🤔 What does ctr + d
do?
It sends an EOF (end-of-file) marker, unless disabled by an option, this will close the current shell (EXIT).
Terminal multiplexers like tmux allow you to multiplex terminal windows using panes and tabs so you can interact with multiple shell sessions.
The most popular terminal multiplexer these days is tmux
. To operate tmux you'll have to learn keybindings.
tmux terminology:
🤔 What is emacs
?
The extensible, customizable, self-documenting, real-time display editor (aka a powerful and highly customizable text editor)
alias
A shell alias is a short form for another command that your shell will replace automatically for you. You can alias a command to that same command with your favorite flags: e.g. mv -i
Examples of programs with dotfiles:
bash
- ~/.bashrc, ~/.bash_profilegit
- ~/.gitconfigvim
- ~/.vimrc and the ~/.vim folderssh
- ~/.ssh/configtmux
- ~/.tmux.confssh
Stands for Secure shell and is a program for logging into a remote machine and for executing commands on a remote machine.
ssh username@remote_host
Connect to a remote server.
ssh-keygen
To generate ssh
keys.
Shoutout to tldr and dashdash for making the man
files much easier to work with👍!
Note, I have tldr
aliased to help
, it's much easier to type! (my other bash alias
es).
.
means “any single character” except newline*
zero or more of the preceding match+
one or more of the preceding match[abc]
any one character of a, b, and c(RX1|RX2)
either something that matches RX1 or RX2^
the start of the line$
the end of the linegreedy matching is to match as much as you can. Add a ?
to make matching non-greedy.
capture group is any text matched by a regex surrounded by parentheses and stored in a numbered capture group ( \1
, \2
, \3
).
Edit (find
& replace
) text in a (non-interactive) scriptable manner.
echo "Welcome to the jungle" | sed 's/jungle/party/'
Find the string jungle
and replace it with string party
.
sed 's/jungle/super party/' jungleFile
Find the string jungle
(inside the file jungleFile
) and replace it with super party
.
sed 's/jungle/super party/gi' myfile
Find all occurrences of the string jungle
and replace them with super party
(ignoring character case).
sed -n '5,10p' myfile.txt
Return lines 5 to 10 inside the file myfile.txt
.
sed '20,35d' myfile.txt
Return all of the file except for lines 20-35 inside the file myfile.txt
.
sed
’s regular expressions are somewhat weird, and will require you to put a \
before most of these to give them their special meaning. Or you can pass -E
.
sed "s/[aeiou]/*/g" myfile.txt
Find all vowels and replace them with *
.
sed 's/[aeiou]/\u&/g' birthday.txt
&
is the capture group, \u
makes all the vowels uppercase.
wc -l file
Count lines in file.
wc -w file
Count words in file.
sort filename
Sort a file in ascending order.
sort -r
In reverse order
sort -n
Will sort in numeric (instead of lexicographic) order
sort -r filename
Sort a file in descending order.
uniq -c
Will collapse consecutive lines that are the same into a single line, prefixed with a count of the number of occurrences
sort file | uniq
Display each line once.
sort file | uniq -d
Display only duplicate lines.
For editing column data.
Awk assigns some variables for each data field found:
$0
for the whole line.$1
for the first field.$2
for the second field.$n
for the nth field.Fun alert!
history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n10
Display 10 most frequently used bash commands from history.
xargs
Takes a list of inputs and turns them into arguments. Execute a command with piped arguments coming from another command, a file, etc.
ls CC* | xargs wc
Print the number of lines/words/characters in each file in the list
find /tmp -name core -type f -print | xargs /bin/rm -f
Find files named core in or below the directory /tmp and delete them. Note that this will not work correctly if there are any filenames containing newlines or spaces.
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
Find files named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly handled.
find /tmp -depth -name core -type f -delete
Find files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example.
💪 My own legit and tested example:
find . -iname 'IMG*.jpg' -mtime -20 | xargs exiftool -All=
Find (case insensitive) all images that start with IMG
, less than 20 days old and remove their EXIF data.
less
Open a file for interactive reading, allowing scrolling and search.
bc -l
Run calculator in interactive mode using the standard math library:
]]>Esc
)i
)R
)v
, line V
, or block ctrl+v
): for selecting blocks of text:
):q
close the current window:qa
close all windows (quit Vim):q!
close and discard any changes you've made (force-quit):w
save:wq
save and quit:help [topic]
open help (:help :w
opens help for the :w command):e
[name of file] open file for editing:ls
show open buffershjkl
(left, down, up, right)w
(next word), b
(beginning of word), e
(end of word)0
(beginning of line), ^
(first non-blank character), $
(end of line)H
(top of screen), M
(middle of screen), L
(bottom of screen)Ctrl+u
(up), Ctrl+d
(down)gg
(beginning of file), G
(end of file)f[character]
, t[character]
, F[character]
, T[character]
(Find and To)
%
(find the corresponding item - brackets, quotation marks etc)/[regex]
, n
/ N
for navigating matcheso
/ O
insert line below / aboved[motion]
delete [motion]
dw
is delete word, d$
is delete to end of line, d0
is delete to beginning of linedd
deletes the whole linecw
is change wordx
delete character (equal do dl
)r
[character] replaces the current character with the one you typedu
to undo, ctrl+r
to redoy
to copy / “yank”p
to paste~
flips the case of a character (or selection)V
) you'll be selecting by lines at the timectrl+v
) you'll be selecting by rectangular blocksTo perform a given action a number of times.
3w
move 3 words forward5j
move 5 lines down7dw
delete 7 wordsParticularly useful for changing stuff inside/around brackets, quotes.
i
, “inside”, and a
, “around”.ci(
change the contents inside the current pair of parenthesesci[
change the contents inside the current pair of square bracketsda'
delete a single-quoted string, including the surrounding single quotesfoo=bar
Declaring a variable.
echo $foo
Accessing a variable.
❗ Spaces are reserved for separating the arguments (foo = bar
is an invalid declaration).
For literal strings, double or single quotes are equivalent.
But, variables won't expand inside single quotes (but yes in double-quotes)
'Value is $foo'
⛔"Value is $foo"
✅Function example: (mcd
- create and cd
into that folder)
mcd () {
mkdir -p "$1"
cd "$1"
}
source [function name]
Execute commands from a file in the current shell.
source path/to/file
Evaluate the contents of a given file.
$0
The name of the script we are running.
$1
Access the 1st argument.
$#
The number of arguments we are giving to the command (length
).
%_
The value of the last argument.
!!
Run the last command again (often used with sudo
).
$?
Read the value of standard error. (false
produces error
code 1).
$$
Process id.
$@
Expands to all the arguments (spread).
;
To concacenate different commands in the same line.
false || echo "Oops, fail"
(prints Oops, fail)
true || echo "Will not be printed"
(prints nothing)
true && echo "Things went well"
(prints Things went well)
false && echo "Will not be printed"
(prints nothing)
true ; echo "This will always run"
(prints This will always run)
false ; echo "This will always run"
(prints This will always run)
Process substitution feeds the output of a process (or processes) into the stdin of another process.
cat <(ls) <(ls ..)
<( CMD ) will execute CMD and place the output in a temporary file and substitute the <() with that file’s name.
Evaluate condition.
If it is true, returns 0 exit status, otherwise returns 1.
test -z \$GIT_BRANCH
Test if given variable is empty.
test -e filename
Test if file exists.
Globbing or filename expansion: Filename expansion means expanding filename patterns or templates containing special characters.
For example, example.???
might expand to example.001
and/or example.txt
.
touch foo{1,2,10}
touch {foo,bar}/{a..j}
Functions have to be in the same language as the shell, while scripts can be written in any language. This is why including a shebang for scripts is important.
Functions are loaded once when their definition is read. Scripts are loaded every time they are executed.
Functions are executed in the current shell environment whereas scripts execute in their own process
shebang
The first line in the script that will inform the shell how to run this program.
foo=$(pwd)
Saves the output of the pwd
command in the foo variable: echo "We are in $(pwd)
/dev/null
If you redirect output there, it will be discarded (this is so for tidying up your output)
ctrl + r
Backward search (press ctrl + r again to go through the results)
brew info [tool]
👍 To look it up on Homebrew.
shellcheck (For bash script debugging)
imageMagick (Tools and libraries to manipulate images in many formats)
ffmpeg (Play, record, convert, and stream audio and video)
find
find . -name src -type d
find . -mtime -1
(modification time in the last day )
find . -naame "\*.tmp" -exec rm {} \;
fd (Simple, fast and user-friendly alternative to find)
ripgrep (For more colorful grep.)
rg -C 5 emoji src
(Get 5 lines of context.)
history | grep convert
fzf (Type fzf to search over all your files.)
tree (Display directories as trees (with optional color/HTML output))
broot (New way to see and navigate directory trees)
bash
(Bourne Again SHell) is a common shell that comes preinstalled on many OS.
date
- current date
cal
- calendar
echo $PATH
Shows all the paths on your machine that the shell will search for programs (it's a colon-separated list).
which echo
Tells you where a specific program is run from.
PATHS are a way to "name a location of a file on your computer".
Absolute paths are paths that fully determine the location of a file.
Relative paths are relative to where you currently are (pwd
).
If you want to create a directory/file with spaces:
\
echo Hello\ World
.
(the current directory)..
(the parent directory)~
(the home directory)cd -
(previous directory)Anything that doesn't take value is a flag, and everything that does is an option.
-a
and --all
(flags)
-c
and --color
(options)
in man
documentation:
...
(means 1 or more)
[]
(means options)
In terms of users: owner, group, everyone else.
Directory permissions (rwx))
-read
: think of it as a list (can you see files inside a folder)
-write
: are you allowed to rename, create or remove files within that directory
So if you have write
permissions on a file, but not the directory in which the file is, you cannot delete that file (you can empty it, but you cannot delete it!)
-execute
: think of it as search. Are you allowed to enter this directory (CD into it). You need to have execute
permission on all the parent directories as well!
-
indicates that the given principal does not have the given permission"When a program tries to read input, it reads from the input stream, and when it prints something, it prints to its output stream. "
>
(append)
>>
(overwrite)
|
(takes the output of the program to the left and make it input of the program to the right)
sudo su
Run root shell - you'll see the #
prompt (instead of $
) at the end of your prompt.
Run the following command and shell as superuser
tee
Read from standard input and write to standard output and files (or commands). Tee takes it's input and writes it out to a file + it writes to the stdout.
-chmod u+x file
Give the [u]ser who owns a file the right to e[x]ecute it:
]]>webpack
, so I skipped most of the tips concering webpack
configuration.
In Performance, once you've recorded a profile, go to Timings too see which components were rendered and when (good for debugging) - unfortunately this will be removed from React link.
Component renders: Go to React DevTools settings and check "Highlight updates...". Now, whenever you do something, every component that re-renders will flash for a bit.
Another way to figure out why a component re-renders is to use why-did-you-render
.
preact
+ preact-compat
(react-dom
is the single largest dependency. Just by removing it, you can reduce your load time quite significantly).Compress them using Cloudflare ($20/month), use Polish option.
Optimize image sizes with <img srcset>
(don't serve gigantic images for tiny screens).
Subset fonts for loading the fonts faster with subfont or glyphhanger.
If you’re preloading fonts, make sure you use the crossorigin="anonymous"
attribute (without that attribute, preloaded fonts will be ignored).
A great way to speed up custom fonts is to use font-display
(more details).
For older websites add &display=swap
(or another value) parameter to get font-display
benefits.
To see how much of your CSS and JS has been used to render a page: DevTools → Ctrl/⌘+P → Coverage → "Start instrumenting...".
bundle buddy shows duplicated modules
also bundle wizard
Moments.js: day.js is similar but smaller.
lodash
: babel-plugin-lodash transforms your Lodash imports to make sure you’re only bundling methods that you actually use (= 10-20 functions instead of 300).
Try aliasing lodash-es
to lodash
(to avoid lodash being bundled multiple times).
Check how much they are affecting your loading speed: Network → Sort by domain → Right-click each third-party → Select "Block request domain". Then run lighthouse audit to compare.
setTimeout
.Type -has-response-header: Content-Encoding
into the filter in the Network panel to see if resources are missing gzip/Brotli compression.
Speedier navigation: getquick (preloads links when the visitor hovers them. this gives a 100-300 ms head start), instantclick (goes further and preloads all links within the viewport).
To check whether all requests use a single HTTP/2 connection, or something’s misconfigured, enable the "Connection ID" column in DevTools → Network.
Use polyfill.io to reduce the amount of polyfills.
If you have any scroll
or touch*
listeners, make sure to pass passive: true
to addEventListener, more here.
A templating language is like a preprocessor for HTML (what SASS is to CSS) 👍.
Template engines are tools that help us break HTML code into smaller pieces that we can reuse across multiple HTML files.
They also give you the power to feed data into variables that help you simplify your code (from).
Why use it?
Can be .njk
but also just .html
.
This is how you write variables:
also
You can also do if
and for
and other stuff (just like in JavaScript).
Filters are functions (note the |
). Filters can be builtin or made by you.
Some built-in filters:
Template inheritance is where nunjucks really shines!
include pulls in other templates in place (especially partials)
extends allow you to define a template document with “blocks” inside of it that are meant to take chunks of content.
this allows us to define a base template, and then override parts of it within the child template. This is known as template inheritance.
shift + (left/right) arrow
Select character by character.
alt + (left/right) arrow
Navigate word by word.
alt + shift + (left/right) arrow
Select word by word.
option + delete
Remove word by word.
cmd + (left/right) arrow
Move to the beginning/end of the line.
cmd + shift + (left/right) arrow key
Select/unselect line.
shift (up/down) arrow
Select line by line.
cmd + shift + k
Delete the current line.
cmd + x
Cut a line.
cmd + shift + enter
Insert a line above.
cmd + backspace
Delete a line.
option + (up/down) arrow
Move a line up or down.
option + shift + (up/down) arrow
Copy line up or down.
cmd + l
Select the current line; keep pressing -l to expand selection downward.
option + shift + (left/right) arrow
Expand or shrink selection.
cmd + (up/down) arrow
Go to the top/bottom of a file.
cmd + shift + (up/down) arrow key
Select/unselect entire file.
ctrl + tab
Go to the next opened tab.
shift cmd + t
Open a previously closed file.
cmd + shift + \
Go to the matching opening/closing bracket.
cmd + shift + o
Navigate by symbols.
cmd + [
or cd + ]
cmd + /
cmd + z
and cmd + shift + z
cmd + \
Split editor.
cmd + num
Focus a specific editor window.
ctrl + g
cmd + shift + p
(or F1
) to access the command palette, then run sort lines.
cmd +f
Search in the current document.
cmd + shift + f
Search in the current workspace.
cmd + shift + h
Toggle replace mode.
cmd + click
Insert cursor (press Escape
to remove the temporary cursors).
cmd + d
Select the next match.
cmd + u
De-select previous match.
cmd + .
To open the quick-fix context menu.
F8
Go to the next error warning.
cmd + shift + p
Open the command palette, then run all tests?
cmd + k + z
Enter the zen mode.
cmd +
Toggle between different VScode workspaces.
cmd + option + s
Save all tabs.
I wrote about VScode Keyboard Shortcuts previously.
]]>ctrl a
and ctrl e
For moving to the beginning/end of the line (just like in your terminal/command line!)
cmd + l
Bring the URL bar into focus.
cmd + enter
Duplicate the current tab (while in URL focus).
cmd + shift + t
Open a tab you just closed (a lifesaver for my trigger-happy fingers).
cmd + d
Add a bookmark (extra tip: when saving bookmarks to the bookmarks bar, delete all the text meaning only an icon will get displayed => you can cram many more bookmarks into your bookmarks bar 💪).
cmd + shift + c
Toggles the inspect element mode (and makes for faster DOM inspection).
Toggle the console
from dev tools by pressing esc
key.
cmd+ option + i
To open the dev tools (in the last panel you used).
shift + enter
For a multi-line entry (in the Console
)
cmd + [
and cmd + ]
To focus next/previous panel in the dev tools.
cmd + shift + d
Switch back to whatever docking position you last used.
cmd + shift + p
Open the Command Menu.
console.log
values? Wonder no moreGo to the console, right-click on the logged value and click Store as Global Variable.
Now, this value will be stored in a variable temp1
(temp0
in Firefox). Nuts!
The subsequent values (in the same session) will be stored astemp2
, temp3
...
To get that data onto your clipboard type: copy(temp1)
🤯
cmd + shift + p
To start private browsing.
cmd + k
Move focus to the Search bar.
cmd + up/down arrow
Go to the top/bottom of a webpage.
]]>padding
)margin
)Margin collapse happens when two vertical elements have a margin, and one of them has a greater margin than the other. In that case, the greater margin will be used, and the other will be ignored.
🔨 To fix: Use a single direction margin, e.g.:
.element:not(:last-child) {
margin-bottom: 1rem;
}
🤔 If both the parent and the child have a margin, the child's margin will be collapsed.
🔨To fix:
border
to the parent element ORdisplay
to inline-block
ORpadding-top
to the parent element.Vertical padding doesn’t work with elements that have display: inline, like <span>
or <a>
.
🔨 To fix: need to do display: inline-block;
Learn about Right to Left styling.
Flexbox doesn't have a gap property, like grid-gap
.
🔨 to fix:
padding-left
to the grid item ANDmargin-left
with the same padding-left value to the grid parent.The reason: because the first card has padding-left while in reality it’s not needed. So it will push the wrapper to the left and cancel that unneeded space (Demo).
The last element should not have a bottom margin, as margin should only be between elements.
🔨 To fix: cancel the unneeded spacing by adding a negative margin to the parent element.
vmin
Viewport Minimum (vmin) – A percentage of the viewport width or height, whichever is smaller. 10vmin will resolve to 10% of the current viewport width in portrait orientations, and 10% of the viewport height on landscape orientations.
vmax
Viewport Maximum (vmax) – A percentage of the viewport width or height, whichever is larger. 10vmax will resolve to 10% of the current viewport height in portrait orientations, and 10% of the viewport width on landscape orientations
grid-gap: min(2vmax, 32px);
Use a gap equal to 2vmax, but it shouldn’t go above 32px.
]]>autojump (for quick navigation)
bat
(cat
with syntax highlighting)
htop (for process management)
gist (for making gists!)
youtube-dl (for downloading youtube videos)
zsh
theme)http-server (for spinning up a simple server from the command line)
nodemon (automatically restarts a node
application on change)
tldr (for simpler man
pages)
Alfred (mostly for opening applications (no fancy workflows))
Flux (to prevent my eyes from dying)
Karabiner-Elements (for keyboard remapping)
Rocket emoji (for writing emojis really quickly)
Spectacle (for resizing windows)
Vanilla (for cleaning up the menu bar)
.github/pull_request_template.md
Create this file and directory at the root of your project. Once you've written the template, make sure to merge onto your default remote branch.
.github/ISSUE_TEMPLATE/feature_request.md
This is where your template will live. Besides the markdown content, the template requires frontmatter
.
---
name: Feature Request 💡 (name of the template)
about: Suggest a new idea for the project. ( template description)
labels: enhancement (default template labels)
---
.github/CODEOWNERS
Create this file at the root of your project.
Add GitHub users (*
means they will be global owners - a.k.a. the default owners for everything in the repo).
Go to GitHub, Settings, scroll down to Merge button, select "Allow squash merging".
Go to GitHub, Settings, scroll down to Merge button and select "Automatically delete head branches".
brew install github/gh/gh
To install it on macOS.
gh repo view -w
Open a Repo in Browser using GitHub CLI.
alias repo='gh repo view -w'
My alias
💪.
stat [file]
Show file properties such as size, permissions, creation, access dates and more!
type [alias]
To quickly check what your alias
does.
echo $PATH
To see the list of executables.
export PATH="$PATH:~/scripts-folder"
To add a folder to the executables (that way you'll be able to run your scripts from anywhere).
ln -s ~/scripts-folder/script /usr/local/bin
You can also create a soft link to the usr/local/bin
(where your scripts should generally live).
cp index.js{,.backup}
This will create a file called index.js.backup
with the contents of index.js
touch test-{1..10}
Will create 10 test files starting with test-1
. Not all commands accept multiple inputs, but touch
does.
!!
Run the last command again.
!$
Gives you the last argument of the previous command.
ctrl + a
: go to the beginning of th line.ctrl + e
: go to the end of the line.ctrl + k
: to delete the line up to the cursor.ctrl + w
: delete the last word.curl -s https://api.github.com/repos/edieblu/includeJS.dev | jq '.stargazers_count'
Get the numbers of stars in a GitHub repo.
jq
for dep in $(jq -r '.dependencies | keys | .[]' package.json); do
if ! grep "required\(.*$dep.*)" Rq --exclude-dir="node_modules" ." then
echo "You can probably remove $dep"
fi
done
Use jq and grep to find unused dependencies.
keys
: to get just the keys out of the jq object.[]
: array value iterator to get the values in a separate liner
: flag in jq means raw text (no quotations)Rq
: recursive and quietexec
Changes where stdout
and stderr
go for all commands that come after it.
exec >> log/hooks-out.log 2>&1
Append standard error
to the same place and in the same mode than standard output
is in.
git diff
if git diff-tree --name-only --no-commit-id ORIG_HEAD HEAD
This will return the differences between the previous and current commits as a bare list of files.
if git diff-tree --name-only --no-commit-id ORIG_HEAD HEAD | grep --quiet 'package.json'; then
echo "$(date): Running npm install because package.json changed"
npm install
else
echo "$(date): No changes in package.json found"
fi
Check if package.json
has been changed and run npm install
if it did.
npm install > /dev/null
If you output to /dev/null
the output will be discarded. Note that errors will still be outputed.
case "$1" in
*.tar|*.tgz) tar -xzvf "$1";;
*.gz) gunzip -k "$1";;
*.zip) unzip -v "$1";;
*)
echo "Cannot extract $1"
exit 1
;;
esac
A script that extracts a file archive, depending on the file extension.
#!/usr/bin/env node
This tells the shell to use the node
binary in your environment to execute this file.
.plist
A .plist
file is an XML
-formatted file for macOS.
~/Library/LaunchAgents/
List all applications with job configuration.
Define your design choices in advance. Stick to them. Write them down. Use CSS variables. This goes for:
font-size
(use rem
)font-weight
(avoid going under 400)line-height
(and letter spacing)color
(grays, grays, grays)margin
(spaaaaaaace)padding
(moar spaaaaaaace)width
(lots of skinny pages these days)height
box-shadow
(shadows... 😅)border-radius
border-width
opacity
font-family
Don't reinvent the wheel - stick to popular fonts (especially if you're still training your design eye).
Borrow from others.
Often time you'll pair a sans-serif
header typeface with a serif
body typeface.
👍 Pro-tip: Ignore typefaces with less than five weights.
2,3 fonts max!
Typeface VS font?
Fonts and font pairing resources:
You can do so much with fonts these days (in a modern browser): Font variable experiments
font-weight
The weight has to do with the thickness of the font, the style (italic, oblique) normally has to do with the angle.
A normal font-weight
of 400 or 500 (depending on the font) shoudl be used for most text.
A heavier font-weight
of 600 or 700 for the text you want to emphasize.
Values range from 100 to 900:
line-height
line-height
should be about 1.5x for body font (meaning you multiply font-size
by 1.5).letter-spacing
letter-spacing
is the amount of space between a group of letters (there's also word-spacing
💡).margin
and padding
font-size
.width
em
.alias
-es. I will write about my oh-my-zsh
theme settings and plugins in another post 👍.
My zsh
aliases are written in a separate file and loaded in my .zshrc
file like so:
source $HOME/dotfiles/zsh/aliases.zsh
I'm using homebrew
as my package manager.
alias help="tldr"
Because those man
pages can be quite intimidating, I prefer to use tldr for the first, quick glance.
alias top="sudo htop"
Interactive process viewer - to see what's hogging your memory. Good for killing processes fast!
alias yt="youtube-dl"
For quickly downloading youtube content. More about youtube-dl
here.
alias reload="source ~/.zshrc"
For quickly reloading your zshrc
config.
alias finder="open -a Finder ./"
Open your current directory in Finder (I'm not super good with copying and moving stuff around in terminal yet).
alias weather="curl -4 https://wttr.in/Brussels"
Check out the weather in your city.
alias cat='bat'
cat
with syntax highlighting and other stuff. More about bat
here.
alias md='mkdir -p'
Make a new directory only if one (with the same name) doesn't exist yet.
alias please=sudo
Because being polite is cool.
alias d='dirs -v | head -10'
Display the last ten directories.
I wrote about them here.
]]>shift + enter
Create a new line in your message ('Enter' is for sending).
up arrow
Edit your last message.
cmd + u
To upload files (I use this one all the time for sharing screenshots of my work in progress).
cmd + shift + enter
Create a new code snippet. 💡Use single backticks for inline code and tripple backticks for a short code snippet.
/away
To toggle away status (useful for when you want to take a peek at your Slack group, but not be seen as online).
cmd + shift + y
Edit your status - to quickly tell your team that you are unavailable.
cmd + shift + a
Open all unreads. (Meh, not sure yet whether this one is useful for me).
alt + up arrow/down arrow
Navigate up and down channels or DMs 💪.
cmd + number
To switch between different slack groups 💪.
cmd + k
Quick switcher (sort of like command palette in VSCode).
cmd + /
Toggle the keyboard shortcuts panel.
/remind [who] [what] [when]
To set reminders in Slack.
Pro tips:
I use Rocket emoji for all my emoji dispensing.
Add Giphy for Slack for GIF posting via /giphy
command.
git
commands previously here and here.
Besides the Smashing Magazine link from above, I've also picked up a couple of tricks from Harry Roberts' and Git Explorer.
git branch --sort=-committerdate
Sort branches by date.
git checkout -
Checkout previous branch (-
is same as @{-1}
).
git branch -vv
List branches along with commit ID, commit message, and remote.
git status -sb
Git status that is easier to read (I have a gs
alias for that).
git reflog
To see the history of all of your git
activity
git log -- missing_file.txt
Find files (even ones that were deleted).
git shortlog -sn --all --no-merges
To see who has committed how much 💪.
git shortlog -sn --since='10 weeks' --until='2 weeks'
In a specific range.
git for-each-ref --count=10 --sort=-committerdate refs/heads/ --format="%(refname:short)"
See 10 most recent branches recently worked on.
git commit --amend --no-edit
Modify the last commit, but leave the commit message. (I will marry this one!)
git diff --staged
Show commited/staged changes.
git diff [commit1] [commit2] | less
Compare two commits and output the result in the terminal.
git stash show -p [stash id]
View contents of a stash. Very useful for a notorious stasher like me!
]]>cmd + shift + \
For finding a matching bracket (especially useful if you're not using an extension that does that for you - like Rainbow Brackets).
cmd + p
Quick open, go to file.
cmd + p + p
Toggle back and forth between two files (equal to ctrl + tab
).
cmd + .
To toggle the auto-fix menu (for fixing indentation, etc.). This is especially useful if you're not using Prettier.
cmd + 0
Bring focus to the sidebar. cmd 1
to bring the focus back to the code editor.
ctrl + [num]
Jump from tab to tab (e.g., first tab is ctrl + 1
).
F2
Toggle rename mode: this will change the name of that constant wherever it occurs (great for refactoring).
F8
Go to the next error or warning.
F12
Go to the definition (great for exploring the codebase).
cmd + down arrow
Open a file while in file explorer (pressing the enter key will rename the file).
cmd + d
Select multiple instances.
alt + up arrow
Move a line of code up (you can move it down with the down arrow instead).
shift + alt + down arrow
Duplicate lines of code down (you can do it upward, by using the up arrow instead).
alt + right arrow
Navigate the code, word by word going right (you can go left by using the left arrow instead).
cmd + right arrow
Jump to the end of the line (cmd + left arrow
for the beginning of the line).
cmd + l
Select the current line. Press the l
key repeatedly to select more lines (expanding downward).
cmd + shift + k
Delete the current line.
cmd + shift + enter
Insert a line above.
cmd + [
Increase indentation (with closing square bracket to decrease indentation).
cmd + up arrow
Jump to the top of the file (use the down arrow to jump to the bottom of the file).
ctrl + g
Navigate to a specific line number.
cmd + backspace
Delete everything and place cursor to the start of that line.
cmd + k + v
Open markdown preview (for markdown files).
cmd + shift + .
Open breadcrumbs.
cmd + p
then @
Go to the command palette, then press @
to navigate to the different sections of the file.
cmd + down arrow + .
Open the file (through directory explorer). Pressing enter
will toggle the rename mode.
cmd + k + j
Open a Quokka workspace - prototyping playground.
cmd + ,
Go to user settings.
cmd + k + cmd + S
Open keyboard shorcuts.
alt + w + w
Close all files and collapse the directory tree.
capslock + right arrow
I'm using capslock
as an extra modifier key (via Karabiner-Elements), this combination splits the screen horizontally to the right (useful for comparing two files).
capslock + F
Toggle full screen.
]]>less [filename]
Open a file for interactive reading, allowing scrolling and search.
/searchTerm
To search inside less
, press /
followed by the search term.
open [filename] -a TextEdit
Open a file with the specified application.
echo 'hello' > file.txt
Creates and initializes a file.
mv lib/* src/
Move everything from the lib
folder to the src
folder.
cp -R src/* lib/
Copy everything from the lib
folder to src
folder.
find images/ -iname "*.png"
Find all .png
files in the directory (-i
flag for case insensitive).
find . -type d
Find all the folders.
find dist/ -name "*.builts.js" -delete
Find them and destroy them.
grep --color -n "npm.config.get" lib/npm.js
Will do a numbered & colorized output.
curl -iL URL
The -i
include flag will output the header. -L
for following redirects.
curl -H "Authorization: Bearer 123" localhost...
Add an authorization bearer token.
curl -X POST "Content-Type: application/json" -d '{"title": "Curling", "author":"Cameron"}'
-X
to change from the default GET
request to a POST
request. -d
flag for data
.
curl -i -X PUT \
For a multiline request, you can add \
to the end, followed by the Enter
key. Continue writing the request in the new line.
curl -iL https://google.com -o google.txt
Output the response into a text file.
echo "Initializing JS project at $(pwd)"
git init
npm init -y # create package.json with all the defaults
mkdir src
touch src/index.js
code . # open src/index.js
A bash
script for scaffolding a simple JS project. For scripts, you need to chmod u+x
to be able to execute them and then ./[filename]
to run them (or move the script to /urs/local/bin/[scriptname]
to execute it globally).
ENV
Will display all your global environment variables.
temp=$(mktemp -d)
git clone --branch $1 $pwd
echo "branch $1 cloned to $temp"
Clone from a local Git
repository branch to a temporary folder.
echo $?
Echo the exit status of your last command.
if [[ -z $USER ]]; then
echo "true"
else
echo "false"
fi
A simple conditional script.
check_status() {
local status = $(curl -ILs https://example.org | head -n 1 | cut -d ' ' -f 2)
if [[ $status -lt 200 ]] || [[ $status -gt 299 ]]; then
echo "$1 failed with a $status"
return 1
else
echo "$1 succeeded with a $status"
fi
}
Curl a URL
and check if it responds with a 200 range status. The complicated bit is just cutting the status code from the curl
response header.
bash
is a unix
(an operating system that evolved into Linux) shell. A shell is a computer program that is used to launch other computer programs ( via a text interface). bash
comes from 'bourne again shell'.
ls -1
display directory content, line by line.
cd
is the same as cd ~
reset
to reset your terminal 👍
mv moby-dick.txt{_,}
will expand to: mv moby-dick.txt_ moby-dick.txt
You can always test what your command will do (without actually doing it), by adding echo
- this will output just the expansion.
mkdir -p
The -p
flag will create a directory if one doesn't exist yet.
cat b{ee,oo}p.txt
img{0...100}
Will generate 100 directories like img0
, img1
etc.
>> file.txt
Append to file.
ls -l *.txt | wc -l
Will count the number of .txt
files in the current directory.
sed -r 's/\s+/\n/g'
Converts all whitespace (tabs, spaces, newlines) into newlines.
cal
Displays the calendar.
cal November 2020
cal -3
Shows previous months, current month, next month.
date
date +F
Today's date in year-month-date format.
echo 'date'
(with backticks) is the same as echo $(date)
If you run curl -s
the -s flag will get rid of the progress bar. 👍
#!/bin/bash
You need to put that on the first line of your bash scripts.
touch logger
You can add a .sh
extension to your scripts, but not needed.
echo date + '%F %T'
$1 >> date +%F
.logAppend a message to a file with today's date (a logger of sorts). $1
is the variable.
chmod +x logger
You need to make the script executable. 👍
You can use $*
(instead of $1
) to grab the whole input - for multi-word inputs. If you are using $1
, you'll have to add ''
. 👍
while true; do node server.js; done
Restart the node server every time it crashes.
usr/local/bin
Where your scripts should live.
sudo cp logger /usr/local/bin/loggy
Copying our script to the scripts folder. From now on, we can execute it from anywhere by typing loggy
.
echo $?
Read the exit code of the program you've just executed (0 means no error, non-zero fo unsuccessful).
test -f
Evaluates the expression and, if it evaluates to true, returns a zero (true) exit status; otherwise, it returns 1 (false). -f
: True if file exists and is a regular file.
ctrl c
Stops the process.
ctrl z
Puts the process in the background. You can revive it with fg
👍.
pgrep
Search for a process by its name.
pkill -9 [process name]
Kill all processes which match process name.
regex in JavaScript
:
str.split(re)
str.match(re)
str.replace(re)
re.test(str)
re.exec(str)
flags:
i
case insensitiveg
match all occurrences (global)m
treat a string as multiple liness
treat a string as a single linemetacharacters:
.
matches any character
?
zero or one time
*
zero or more times
+
one or more times
[]
character class
^
anchor at the beginning
$
anchor to the end
(a|b)
match a or b
()
capture group
(?:)
non capture group
\d
digit [0-9]
\w
word [A-Za-z0-9]
\s
whitespace [\t\r\n\f]
sed -E
and grep -E
to escape metacharacters
sed -E 's/[0-9]+//'g
remove all the numbers
'cool "beans" zzz'.replace(/"[^"]+"/, 'XXX')
Replace everything between double quotation marks with XXX.
sed -E 's/(\w+) \1/\1/g'
Remove duplicates (only if they are next to each other).
sed 's/cool/k00l/g' -i file.txt
Replace cool with k00l in the file specified.
navigation (also used in less
)
k
upwardsj
downwardsl
right sideh
left sidels -ltr
l = list, t = sort by time modified, r = reverse results
cd -
Go to the last directory - great for jumping between two directories.
which [application name]
Tells you where the app is running from.
find .
Print all the files in the current directory (including hidden files).
find . | grep .md
Find all markdown files.
find . | grep .md | wc -l
And count how many lines.
find . | grep .md | xargs cat | wc -w
How many words in each markdown file.
find [directory] -mtime -1 -ls
Find all files modified in the last 24 hours.
find [directory] -mtime -1 -ls | egrep .js$ | awk '{ print $1 }'
Find above, but only files ending in .js
and print out the first column.
grep -n [term]
Will show the line number of where the match occurred.
grep -c [term]
Count the number of occurrences.
grep [term] -n -A 2 -B 2
Will print two lines before and two lines after the match.
grep '^#
Find all the headings in a markdown file.
cat [file] | pbcopy
Copy the contents of a file onto the clipboard.
tail -f [file]
Follow the file stream (will continue to print newlines).
less
For file pagination:
👩💻 Make sure to always sort before using uniq (as it only works on neighboring lines).
egrep '^\s+RT @' freezing.log | sort | uniq -c | sort -nr | less
Using egrep
to search for an expression starting with one or more spaces followed by RT @, sort the result, count the number of uniq ones, sort the result by reverse number and pipe into less for easier perusal 💪
vi /etc/sudoers
👩💻 see what sudo powers you have
chmod
and chown
that I didn't pay attention too (since I don't work in shared environments) 😬.
ps auxww | grep [term] -i
Show all running processes.
kill -9
Forced shutdown.
df -h
Disk space.
du -hs
Disk usage for a particular directory (human readable, summary number).
top /htop
uptime
For a quick overview (load averages).
My git
aliases:
ga='git add'
gcm='git checkout master'
gd='git diff'
gp='git push'
gf='git fetch'
gl='git pull'
gs='git-status'
wget [url]
Will save that page to your harddrive.
wget -r -l4 -spider -D [url]
Will recursively save all the pages (spider), 4 links deep, inside a specific domain.
wget ‐‐level=1 ‐‐recursive ‐‐no-parent ‐‐accept mp3,MP3 http://example.com/mp3/
Download all the MP3 files from a sub-directory
wget ‐‐mirror ‐‐domains=abc.com,files.abc.com,docs.abc.com ‐‐accept=pdf http://abc.com/
Download the PDF documents from a website through recursion but stay within specific domains.
curl [url] | scrape p
Would scrape all the p
tags from that page.
curl -I [url]
Returns headers.
curl -L -I -X GET [url]
GET request, get all headers, following redirects.
👩💻 In browser developer tools, Networks tab, you can copy each request as Curl (and then run it locally).
Ngrok
: will tunnel any local port into a public url.
cat [file.json] | json --keys
Will list out all the keys at root level.
json -a
Process array as an object which allows for lookups.
awk '{ print $2 }'
Split the string up by spaces and print the second column only ($0
represents the entire string).
ps auxww | grep node | awk '{ print $1 }'
Find all node processes.
ps auxww | grep node | awk '{ print $1 }' | xargs kill
Find them and destroy them! xargs
takes the pipped in output and takes it as an argument for the next thing.
Get the course github repo and install mongoDB.
To start the Mongo Database server, run mongod
command.
To open the interactive shell, type: mongo
To see existing databases run: show dbs
The following three dbs are created by mongo on install: admin
, config
, local
.
To switch to a database, and create a new one on the fly (if the db doesn't exist yet): use [db name]
To see collections ("tables") in a db: show collections
Download the mongodb GUI to interact with mongo data (Compass).
Use schemas to validate your data and stay consistent. 👍
Random: MongoDB is mostly written in C++, but other languages too.
Use Mongoose to connect your node.js
application to a mongoDB database.
mongodb
port is: port 27017.Use built-in JS primitives as typings. 👍
mongoose.model([collectionName], [schemaName])
Keep the collection names singular and lowercase (mongo will pluralize it). Keep the Model names singular, but uppercase. 👍
Use async/await
for mongodb operations. 👍
Model.create({})
- to insert stuff into the collection a.k.a. creating a mongodb document.
_id
is created by default for any mongodb document. Its value is an ObjectId. (ObjectId comes from BSON and is an object representation of a unique id.)
Mongoose documents are not regular JavaScript objects, they are objects from a database with methods (these might be innumerable - you can't explicitly log them). When you are operating on that data, you'll probably convert them to JSON objects.
Model.find({})
returns a list of result. If you pass in an empty object it will return all (like *
).MongoDB doesn't return errors if things don't exist, it just returns null
. 🤔
Check out other collection methods.
{ timestamps: true}
as the second argument.Queries return a query object. To signal that you're done with a modal query, you attach exec()
to the end of it.
const getUserById = (id) => {
return User.findById(id).exec();
};
With update queries you need to add a second argument to actually return the updated object.
const updateUserById = (id, update) => {
return User.findByIdAndUpdate(id, update, { new: true }).exec();
};
Reference the school model on the student schema:
school: {
type: moongose.Schema.Types.ObjectId,
ref: 'school'
}
.populate()
will inject (hydrate) the corresponding values and return the result as an object."Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s)."
You can also add query filters:
const postByContentLength = (maxContentLength, minContentLength) => {
return Post.find({
contentLength: { $lt: maxContentLength, $gt: minContentLength },
}).exec();
};
Add related posts to a post:
const addSimilarPosts = (postId, similarPosts) => {
return Post.findByIdAndUpdate(
postId,
{
$push: { similarPosts: { $each: similarPosts } },
},
{ new: true }
);
};
get()
or set()
virtuals. ._id
is a built-in virtual.school.virtual("staffCount").get(function () {
return this.staff.length;
});
eventListeners
to any operation that happens (either before - pre
or after - post
, syn or async - any function passing more than one argument).orgSchema.post("remove", async (doc, next) => {
await Project.remove({ org: doc._id }).exec();
next();
});
Use next()
when you have more than one hook. 👍
A compound (unique) index limits the scope of uniqueness to a particular collection:
projectSchema.index(
{
org: 1,
name: 1,
},
{ unique: true }
);
Go to an express route, perform a db operation and send back a response.
app.get("/todo/:id", async (req, res) => {
const todoId = req.params.id;
const todo = await Todo.findById(id).exec();
res.status(200).json(todo);
});
You can use skip()
and limit()
methods for pagination.
Return pure JSOn from your operations by appending lean()
, alternatively you can do the .toJSON()
on the response itself.
Make sure to wrap any async/await
in a try
and catch
statement. 👍
Transactions: that puts all the operations in a queue. "Transactions let you execute multiple operations in isolation and potentially undo all the operations if one of them fails."
I'm relatively new to MongoDB, but this course was a nice overview on how to query, validate and model data in mongoDB. Also, Scott Moss is "legit" 😎.
]]>It's a feature of yarn 2 and it saves up space and installation time by getting rid of your projects node_modules in favor of a .pnp.js
file. The .pnp.js
file points to the location of where the packages are installed (.yarn
file in your project's home directory).
yarn dlx
Is the counterpart to npx
and allows you to run packages without installing them locally (only in yarn 2).
yarn up -i [package]
Yarn 2 is aware of workspaces. Using interactive upgrade, if you have more than one project in the workspace and the same package is used (e.g. React
), you'll be able to choose whether you want to upgrade or keep the package.
Note to self: make sure to escape quotation marks, apostrophe etc in the yaml
frontmatter.
The whole reason I was able to attend was the Outreachy/Mozilla scholarship I received last year. Quick shoutout: if you are new to tech, are from an underrepresented group and want to work with some of the most kickass companies that do open source, you should definitely check it out 💪! They organise paid internship two times a year!
Anyhoo, below are the notes from today's workshop:
1.Custom hooks, baby
Just like with reusable components, you should start building a library of reusable custom hooks, like useBoolean
, useInput
etc. There's also a nifty collection of custom hooks.
2.Ideally, the custom hook should return an object
Abstract the custom hooks (like a util function) and make it return an object - they are easy to destructure and good for avoiding repetition.
3.useEffect is super 💪
useEffect
is used whenever you have a side-effect (like with an event listener). Make sure you get your dependencies right and to remove the side-effect (the event listener, the setInterval
etc) in the return!
useEffect
is more than just a lifecycle hook, for example, the hook will update whenever componentDidMount
and whenever any of the other dependencies you care about changes!
const useDocumentTitle = (title) => {
useEffect(() => {
window.document.title = title;
}, [title]);
};
4.Checkout mobx? 🤔
Kitze swears by mobx, in particular mobx-state-tree. Similar to Redux, but with observables - therefore more performant and with less fiddling around mapstatetoprops
etc.
5.Use ReactContext
, sometimes
For sharing global states (and to avoid passing props to child, to child, to child, to grand-child...). Works great with hooks (and GraphQL
).
For managing lots of state, Redux
is more performant (and apparantely mobx even better - see above).
6.React Compound Component
Smooshing several components together using Context AP
to allow components to somehow manage state among themselves (like Tabs
and Tab
or Select
and Option
).
7.React Controlled Components
Is controlling your components from their parent, but having access to their inner states (kind of like what you are doing with input
and their value
).
8.Use React.lazy
and Suspense
for loading the heavy stuff later
This will make a separate request only once the component is rendered (make sure to provide a fallback a.k.a. skeleton!).
9.useRef to access the previous value
10.And, most importantly
Learn all the keyboard shortcuts, master touchtyping (and keeping an eye-contact while coding), learn everything React
(+optional rant on a slightly more obscure tooling - see above), so that you can do live demos like Kitze 😎.
1.git log | grep 2019
Get commits from 2019 (pipe the log through a filter).
2.git log | grep 2019 | wc -l
Count how many commits were made in 2019 (count the number of lines).
3.git log | grep 2019 | sed -e 's/Date: //' | sed -e 's/\(...\).*/\1/'
To get out the days when the commits were commited (using sed and regex magic).
4.git log | grep 2019 | cut -d ' ' -f 4
Same as above (cut into groups using the delimiter - empty space in this case).
5.git log | grep 2019 | tr -s ' '
Squeezes the output (removes the extra spaces in this case).
6.git log | grep 2019 | tr -s ' ' | cut -d ' ' -f 2
Combines the translate and cut commands to get the same output as number 3. (regex madness from above).
7.git log | grep 2019 | awk '{ print $2 }'
Same result as above, but using awk.
8.git log | grep 2019 | awk '{ print $2 }' | sort | uniq -c
Count the number of occurences of each day (make sure to run sort before uniq, as uniq only removes neighboring duplicates).
8.git log | grep 2019 | awk '{ print $2 }' | sort | uniq -c | sort -n
Sort the final result and add -n
for when sorting numbers.
Final result: (Who would have thunk it, Mondays are the least productive of all weekdays 🤔).
number | day |
---|---|
16 | Sun |
18 | Sat |
278 | Mon |
316 | Fri |
323 | Wed |
351 | Thu |
359 | Tue |
(hey, my first table in markdown 💪!)
]]>git commit --amend -m [commit message]
To fix the commit message (before pushing).
This also works if you want to add more files to a commit.
git log --oneline
Display logs in one line.
git reset HEAD [filename]
To unstage a specific file.
git diff origin/master HEAD
To see the difference between the currrent working directoy and master.
git reset [commit hash] OR git reset HEAD~1
(for one commit back)
It's recommended that you use reset only on branches you haven't pushed yet.
git reset --soft
Undoes the commit, but changes are still staged.
git reset --mixed OR git reset
Removes the commit and unstages the changes.
git reset --hard
Removes the commit, unstages the stages and removes them from the working directory.
git reflog
To see all the changes done in your git repository.
git reset --hard [commit hash]
You will reset to a speficic commit.
git revert [commit hash]
You shouldn't reset commits you've already pushed (that's changing history), instead do a revert.
git branch -vv
Verbose output.
git push --set-upstream origin my-branch
Equal to: git push -u origin my-branch
git cherry-pick [commit hash]
For copying a commit from one branch to another.
git stash pop AND git stash apply
To apply the changes from the stash (apply keeps the changes in the stash). With git stash pop the changes normally go away (but not in case of a merge conflict)
git stash drop [commit hash]
To remove changes from a stash.
git checkout -b branch
If you want to explore a commit, but get rid of the dettached HEAD state, you can checkout the commit as it's own branch.
git remote prune origin --dry-run
Check which branches will be disassociated with the master locally after you've merged them into the remote master. Then run: git remote prune origin and afterwards: git branch -d [branch name]
git rebase -i HEAD~3
To interactively rebase the last three commits.
git rm -r --cached .
Remove all files from the git repository. Afterward run git add . to add them all back in (this is for applying the gitignore file to the files that have been added before gitignore).
git rebase -i HEAD~2
To add a file to a previous commit get into the interactive rebase mode, then choose edit for that specific commit. Do your changes, then do git commit --amend --no-edit (to keep the same commit message) and then git rebase --continue.
git rebase -i HEAD~2
For squashing commits.