The Art Of Lazy Programming

In your time as a Computer Scientist at Rice, you will learn many theoretical aspects of Computer Science and the way to apply programming to complex topics. However, another crucial step towards becoming a great Computer Scientist is efficiency as a developer. The Art of Lazy Programming is a one-credit course where students will be taught precisely that: students will learn vital information every programmer should know, tips on learning complex but time-saving tools, and most importantly, the answer to “how does one master their programming environment and gain the knowledge needed to be an experienced programmer”?

The intention of this class is to teach students various tools and topics such as grep, docker, and sshfs — that will make their life easier by introducing efficiency. While students may learn some of these tools in classes and spend dozens of hours using them, their core benefits are never explicitly taught. Yet, mastering these tools will allow students to solve large-scale problems that seem impossibly complex. Additionally, upon completion of the course, students will also develop problem-solving skills that can be applicable outside Computer Science.

Finally, I advocate for the importance of education. If you are not a Rice student, but would like to learn more about the topics covered in this course, please feel free to reach out to me. I am more than happy to share my knowledge with you.


Week 0 Notes

Week 0 is the first week of the course, where I introduce the course to the class. Watching the video is a great way to skip straight to the content and expectations of the class.


As computer scientists, we know that computers are great at aiding in repetitive tasks. However, far too often, we forget that this applies just as much to our use of the computer as it does to the computations we want our programs to perform. We have a vast range of tools available at our fingertips that enable us to be more productive and solve more complex problems when working on any computer-related problem. Yet, many of us utilize only a small fraction of those tools; we only know enough magical incantations by rote to get by, and blindly copy-paste commands from the internet when we get stuck.

This class is an attempt to address this and close a gap between theory and practice. I intend to teach how to make most of the tools you know, show new tools to add to your toolbox, and instill in you some excitement for exploring (and perhaps building) more tools to be a true lazy programmer.



The basics of bash will be covered in the next lesson. For now, we need to get used to the terminal and the basic commands.

Basic Unix Commands

There are many bash commands, but this short guide is meant to cover the essentials, either as an introduction for those unfamiliar with Unix-based terminals or as a refresher for those more experienced.

Basic Keystrokes and Characters

keystroke / characterfunction
uparrow and downarrowScroll through recently used commands.
tabAutocomplete commands or file names / directories.
ctrl-cKill the current process.
.Hidden file prefix or current directory.
~Home directory.
../Move up one directory.
|Pipe for chaining multiple commands.
>Redirect output to a file.
<Redirect input from a file.
*Wild card character (e.g., use it find all files in the current directory that are Python scripts $ ls *.py).
$Indicate a variable in bash (e.g., $HOME).
ctrl-zSuspend the current foreground process.
ctrl-dExit the current shell (sends EOF).
ctrl-rSearch through command history interactively.
&&Logical AND (e.g., cmd1 && cmd2 runs cmd2 only if cmd1 succeeds).
||Logical OR (e.g., cmd1 || cmd2 runs cmd2 only if cmd1 fails).
!Negate a condition or access the last command that starts with a particular string.
echo- Display a line of text/string that is passed as an argument.
; Command separator (e.g., cmd1; cmd2 runs cmd2 after cmd1 regardless of the outcome of cmd1).


Navigating the terminal requires familiarity with basic commands for directory manipulation, file interaction, and process monitoring. To delve deeper into any command, consult the Unix manuals by entering man command_name.

File and Navigation Fundamentals

  • cd: Change directories (folders).
  • mkdir: Create a new directory.
  • ls: List all files in a given directory.
  • cp: Copy a file from one location to another.
  • scp: Copy files between two machines over SSH, similar to cp.
  • rsync: A more sophisticated method for copying files either locally or over a network, combining the functionalities of cp and scp.
  • mv: Move a file from one location to another.
  • rm: Delete a file. Use -r to remove directories.
  • pwd: Display the current working directory’s path.
  • chmod: Change file permissions.
  • chgrp: Change the group associated with a file or directory.

Probing File Contents

  • cat: Display the entire contents of a file to the command line, useful for small files or as part of a command chain.
  • wc: Count the words in a file, or use -l to count lines.
  • head and tail: Display the beginning or end of a file, respectively.
  • less: Efficiently view large files by loading only a portion at a time. Use arrow keys to navigate, G to jump to the end, g to return to the beginning, / to search within the file, and q to exit.

Process Basics

  • ps: List currently running processes.
  • kill: Terminate a process.
  • htop: Launch a sophisticated process manager, akin to a text-based version of Task Manager on Windows or Activity Monitor on Mac.

Other Useful Commands

  • du -h: Check disk usage with output in human-readable format.
  • wget: Download files from the internet using a URL.
  • curl: Fetch or send data using URL syntax, offering more options than wget. For differences, refer to curl vs wget.

Rust replacements

Ah, I see! You’re interested in Rust projects that reimplement or enhance traditional Unix commands. Here are several well-known Rust projects that serve as modern alternatives or enhancements to classic Unix commands:

Rust Projects as Unix Command Alternatives

  • Exa (ls): Exa is a modern replacement for ls, the traditional Unix command to list directory contents. It features better defaults and is rich in features like git integration and color-coded output. Github Link
  • Ripgrep (grep): Ripgrep is a line-oriented search tool that recursively searches your current directory for a regex pattern. It is much faster than traditional grep due to its efficient use of memory and CPU, and its ability to ignore binary files and hidden directories by default. Github Link
  • Bat (cat): Bat is a clone of cat with syntax highlighting, line numbers, and git integration. It also integrates with other tools like ripgrep to provide a seamless viewing experience. Github Link
  • Fd (find): Fd is a simple, fast, and user-friendly alternative to find. It helps you find files in the file system quickly and efficiently. Github Link
  • Dust (du): Dust is a more intuitive version of du. It shows disk usage and free space in a more comprehensible way by automatically sorting folders by size and visualizing the output in a tree format. Github Link
  • Zoxide (cd): Zoxide is a smarter cd command, learning your habits and allowing you to jump to frequently and recently used directories with fewer keystrokes. Github Link
  • Procs (ps): Procs is a modern replacement for ps. It provides detailed and colored output to make the information more comprehensible. Github Link
  • Skim (fzf/ctrl-r): Skim is a fuzzy finder similar to fzf but written in Rust. It can be used to quickly find files, directories, or even history commands. Github Link

These projects not only replace traditional Unix commands but also enhance them with modern features and better performance, thanks to Rust’s efficiency and safety features.


  • If you wish to use vim keybinds, you can by setting readline to set -o vi in your .bashrc. This allows you to use vim-like editing commands directly in the command line.
  • If you wish to “pause” a command, you can use <C-z> to set the current process to the background. Then when you are ready to unpause, you can use fg to continue your progress.
  • To search through your command history quickly, use <C-r> for a reverse search. Start typing part of the command you’re looking for, and press <C-r> repeatedly to cycle through past commands that match.
  • Customize your prompt to show helpful information like the current directory, git branch, or other useful status by modifying the PS1 variable in your .bashrc.
  • Use alias to shorten commands that you use frequently. For example, you can add alias ll='ls -alF' to your .bashrc to create a shortcut for a detailed listing format.
  • When scripting, use set -e to make your script exit on the first error. This can help prevent errors from cascading and make debugging easier.
  • To preserve your session’s state between logins, consider using a terminal multiplexer like tmux or screen. This is especially useful for remote sessions over SSH.
  • If you find yourself needing the same command frequently but with slight variations, use history | grep <search-term> to quickly find previously used commands without needing to retype them completely.
  • For more efficient navigation, use pushd and popd to work with directories as a stack. This allows you to “push” directories onto your stack as you navigate and “pop” them off to return to previous locations.

Video For Week 0

Week 0 Homework


Please follow the instructions in the Week 0 Installation Guide to install the necessary software and tools for this week.

GitHub Repository Access

To gain access to the team’s repository, please either fill out this form or send me your GitHub username directly. Access the repository sections here:


For instructions on using the command line interface (CLI), refer to the Week 0 Notes. Please note that while the basics of bash will be covered in our next lesson, you are encouraged to experiment on your own in the meantime.

Homework Overview

This week’s homework consists of three parts, focusing more on reading and exercises than coding. Parts 2 and 3 are graded based on completion. All submissions should be made via GitHub to your specific section’s repository.

Submitting Homework

  • Repository Setup: Submit all homework through your section’s repo using the git submodule setup described in the week0 installation guide.
  • Submodule Naming: Name your submodule lastname-firstname.
  • Committing: Commit all your work to your own repo. I will update the main repo during grading. You do not need to commit to the main repo once your submodule is set up.
  • Time Limit: If any assignment takes more than an hour, feel free to skip it.

Part 1: Observation and Installation

  1. Observation Task: Note any differences between your setup and a clear session. Upload your observations to the Week 0 Notes under the filename “part_1_notes.txt”.
  2. Installation Task: Install neofetch and capture its output:
    $ git clone
    $ cd neofetch
    $ make PREFIX=./ install
    Upload the output screenshot to the Week 0 Notes as “neofetch.img”. Example output: Neofetch
    git add part_1_notes.txt neofetch.img
    git commit -m "part 1"
    git push

Part 2: Video Analysis

  • Task: Watch a video segment from this video from 5:00 to 19:00. Take notes and submit them as “part_2_notes.txt”. If possible, watching the entire video is recommended.
    git add part_2_notes.txt
    git commit -m "part 2 notes"
    git push

Part 3: Article Review

  • Task: Read this article by Paul Graham and note anything significant. Submit your notes as “part_3_notes.txt”.
    git add part_3_notes.txt
    git commit -m "part 3 notes"
    git push

Completion: Submitting your assignments will contribute positively to your grade. Ensure you follow the guidelines to ensure your submissions are recorded correctly.

Week 0 Installation Guide

Welcome to Week 0! In this guide, you’ll learn how to log into CLEAR and submit your first assignment. We’ve included specific instructions tailored to different operating systems to ensure everyone can get started smoothly.

Getting Started with Remote Servers

Everyone has their preferred setup for working on remote machines. While you’re encouraged to use what works best for you, we recommend following these guidelines if you’re new to this environment. Be sure to review the basic Unix commands notes to familiarize yourself with the necessary commands. This tutorial is intended for MacOS and/or Linux Users, but instructions for Windows are included.

What is CLEAR?

“CLEAR is a robust and dynamic Linux cluster with exciting features available to Rice students and faculty. The cluster is designed to offer a Linux environment available for teaching and courseware needs.” Specifically, CLEAR is the cluster we will be using for this class, as we’ll all be using Fedora Linux as our environment.

How to Login into CLEAR

To access CLEAR, you need an SSH client (I’ll explain how to install one in the next section). Once you have an SSH client, you can log into CLEAR using the following details:

  1. Host Name: Use
  2. Login Credentials: Enter your Rice NetID and password.
  3. Direct Access: Your home directory on CLEAR is linked to your desktop home from


If you don’t have a home drive when using Clear, please create a ticket in Rice IT with the subject “need clear home directory” to set one up for you.

Installing an SSH Client

Windows Users

If you are on Windows, it is recommended to install the Windows Subsystem for Linux with Ubuntu (WSL). Windows Powershell is now compatible with OpenSSH on Windows 10, however, for optimal server use for our labs, a *UNIX environment is fully preferred. The Windows Subsystem for Linux brings a full Linux experience to Windows 10 with WSL 2 bringing a full Linux kernel to windows. If your computer/laptop does not support virtualization, then a SSH program like putty may be ideal.

Windows Subsystem for Linux

To install WSL, run the following command in PowerShell as an administrator:

wsl --install

For a detailed guide, watch this installation video.

Linux Users

For Linux users, particularly those using Ubuntu, ensure you have the OpenSSH client installed:

sudo apt-get update && sudo apt-get upgrade
sudo apt install openssh-client

macOS Users

Mac users typically have an SSH client pre-installed. If not, or for a more enhanced experience, consider installing iTerm2. Additionally, enabling remote login and installing Xcode can be beneficial:

sudo systemsetup -setremotelogin on
sudo systemsetup -getremotelogin
xcode-select --install


We recommend installing Xcode from the App Store and running xcode-select --install in the terminal to install Xcode command line tools.

Logging into CLEAR

To connect to CLEAR, use the following command:

ssh [your Rice NetID]

Example for Windows:

Doing this successfully will log you into CLEAR. It is important to note that you may need to type your password twice (once for the ssh client and once DUO authentication).

Further Customization and Setup

View the extra notes for more information on how to customize your environment. Specifically, how to log into CLEAR faster and bypass DUO.

Introduction to Git

Git is a version control system that allows you to track changes to your files. Git is a free and open source software distributed under the GPL.

You will be learning about git in this class through the assignments. You may be interested in the guide on First Time Git Setup if you need a refresher on using git in general.

Git and GitHub - Submodule Setup

Think of a submodule as a GitHub repo inside another GitHub repo (i know, woah). Here’s how you can set it up effectively:

1. Create and clone your repo where all your work will be done:

$ git clone
cloning into 'work-test'...
remote: counting objects: 3, done.
remote: total 3 (delta 0), reused 0 (delta 0), pack-reused 0
unpacking objects: 100% (3/3), done.
checking connectivity... done.

2. Clone the main class repo:

 $ git clone
cloning into 'euler'...
remote: counting objects: 14, done.
remote: compressing objects: 100% (9/9), done.
remote: total 14 (delta 5), reused 9 (delta 3), pack-reused 0
unpacking objects: 100% (14/14), done.
checking connectivity... done.

3. Navigate to the appropriate directory in the class repo and add your repo as a submodule:

cd class-repo
git submodule add -b "branch" "url to your repository" "required submodule directory name"

Here is an example:

$ cd euler/
socrates: euler charlie$ cd 04/
socrates: euler/04 charlie$ git submodule add -b main cruz-charlie
cloning into '04/cruz-charlie'...
remote: counting objects: 3, done.
remote: total 3 (delta 0), reused 0 (delta 0), pack-reused 0
unpacking objects: 100% (3/3), done.
checking connectivity... done.

4. Commit and push your changes to the main class repo:

git commit -am "Added submodule for lastname-firstname"
git push

Here is an example:

$ git pull
already up-to-date.
socrates:~/desktop/git_demo/euler/04 charlie$ git commit -a -m "added charlie submodule"
    [master f25eeda] added charlie submodule
2 files changed, 4 insertions(+)
    create mode 100644 .gitmodules
    create mode 160000 randomizer/6/cruz-charlie
    socrates:~/desktop/git_demo/euler/04 charlie$ git push
    counting objects: 5, done.
    delta compression using up to 4 threads.
    compressing objects: 100% (5/5), done.
    writing objects: 100% (5/5), 626 bytes | 0 bytes/s, done.
total 5 (delta 0), reused 0 (delta 0)
    11dc0c6..f25eeda  master -> master

5. Remove the main repo clone if no longer needed:

$ cd ../../
$ rm -rf euler/

Ensure to follow these steps to maintain a clean and organized repository structure for your coursework.

More Tools & Other Recommendations


Set up SSH Keys

SSH keys provide a convenient and secure way to log into remote machines without typing your password. Here’s how to set up your SSH keys, which act as a form of verification for your machine:

$ ssh-keygen


These instructions may not be applicable to Windows users unless WSL is installed.


During key generation, you’ll have the option to enter a passphrase. Choose a passphrase different from your Rice password for security. Use ssh-agent to avoid re-entering this passphrase:

$ ssh-keygen -p  # Set or change your passphrase


If an SSH key already exists, you will see a message like this:

$ /Users/username/.ssh/id_rsa already exists

Security experts recommend using different keys for different purposes. If you replace an old key, remember to update it on any servers that used it.

To manage your private keys (and not have to enter your passphrase every time you SSH), first, start ssh-agent in the background:

$ eval "$(ssh-agent -s)"

Then, add your private key (you will be prompted for your passphrase):

$ ssh-add


You can also add a timeout to ssh-add using $ ssh-add -t 3600 (for a timeout of 3600 seconds) to be extra secure.

For most machines, ssh-agent should start automatically, so when you start a completely new session (e.g., after rebooting your computer), all you should need to do is run ssh-add again, but if ssh-agent has not started, you will need to start it in the background again as well.

To log in to our machines (e.g., risotto) without entering your password every time, you will need to copy your public key to the remote machine. You can do this with the following command, where username is replaced by your Rice net id:

$ ssh-copy-id

If ssh-copy-id is unavailable, manually copy the key:

$ cat ~/.ssh/ | ssh "mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys"

You know can type in your password once per startup session.

Set up SSH Config File - Bypassing DUO Authentication

Writing an SSH config file can streamline SSH connections and avoid having to repeatedly add flags when connecting to machines. If you do not have a config file you first need to create one in ~/.ssh/config.

To enable shorter ssh names, e.g. accessing clear by typing ssh clear vs ssh you need to add additional lines per host to your ssh config (change everything inside the brackets)

Host clear
    User [your_netid]
    PasswordAuthentication no
    PreferredAuthentications publickey


Setting PasswordAuthentication no with PreferredAuthentications publickey helps bypass DUO authentication.

With this setup, you can connect to CLEAR by typing:

$ ssh clear


If you would like to use X11 for GUI displays on the remote server (e.g., using Atom editor), you will need to install X11 on your local machine (XQuartz for macOS and Cygwin for Windows 10). Add the following line under your host definition: ForwardX11 yes

Choose Your Shell

Before you log into our machines, make sure you set your default shell preferences. The default choice is csh, but you can choose between: bash, sh, tcsh, csh, zsh.

We recommend zsh, but you are welcome to choose whatever you feel most comfortable with. To change the default shell for any remote machine, you log into account config (you need to be on the RICE VPN to access this page). Log in with your NetID, then under “Account Maintenance” -> “Shell Management,” you can choose your desired shell environment.

Bash Profiles

Editing shell profiles can save you time and effort by configuring aliases or short cuts for various commands. In addition, it allows for changing the colors of different file and directory types, and adding other convenient functionality.

Since we primarily use bash, we have included some configurations we have found useful that we usually set a priori.

These should be set in your ~/.bashrc file (you may have to create it if it is missing).

Aliases allow you to set shortcuts for frequently used commands. These are some good ones to configure.

alias rm='rm -i'  # Ask before deleting
alias mv='mv -i'
alias ls='ls -G'
alias ll='ls -lthG'  # Detailed listing
alias l.='ls -G -d .*'  # Show hidden files
alias mkdir='mkdir -pv'  # Make parent directories as needed
alias wget='wget -c'  # Continue stopped downloads

Other helpful functions:

# Prevent accidental overwriting
set -o noclobber

# Enhance history features
export HISTCONTROL=ignoredups
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "
export HISTFILE=~/.bash_history_unlimited
shopt -s histappend
shopt -s autocd
shopt -s checkwinsize
shopt -s globstar  # Match files with **

# Color settings for man pages
export LESS_TERMCAP_mb=$'\e[1;32m'
export LESS_TERMCAP_md=$'\e[1;32m'
export LESS_TERMCAP_me=$'\e[0m'
export LESS_TERMCAP_se=$'\e[0m'
export LESS_TERMCAP_so=$'\e[01;33m'
export LESS_TERMCAP_ue=$'\e[0m'
export LESS_TERMCAP_us=$'\e[1;4;31m'

# Enable terminal colors
export TERM=xterm-256color

To view your command history with timestamps, use history. Access the history file directly at $HISTFILE for a detailed log.

Certainly! Below is a section on the Fish shell, detailing its features and benefits for users considering an alternative to Bash.

Choose Your Shell: Why Fish Might Be Your Next Best Friend

When setting up your development environment, selecting the right shell can significantly enhance your workflow efficiency. While Bash is the default shell on many systems due to its long-standing presence, Fish (the Friendly Interactive SHell) offers several compelling features that might make it your shell of choice.

What is Fish?

Fish is a smart and user-friendly command line shell for macOS, Linux, and the rest of the family. Unlike traditional shells, which can be daunting for newcomers, Fish is designed with usability in mind, offering powerful features to both new and seasoned users.

Features That Make Fish Stand Out

  • Autosuggestions: Fish suggests commands as you type based on history and completions, just like a web browser. Watch as Fish suggests commands in real time, allowing you to repeat previous commands faster or use similar commands without remembering every detail.

  • Enhanced Tab Completions: Fish offers advanced completion capabilities. It completes commands, options, and even file paths, reducing the amount of typing and minimizing the guesswork.

  • Rich, Out-of-the-box Configuration: Unlike Bash, Fish works impressively right out of the box. It includes a web-based configuration interface for adjusting prompt colors and functions without the need to edit text files.

  • Extensible and Easy Scripting: Fish’s scripting syntax is simple and clean. For example, there are no $ signs needed for variable expansion. Conditions and loops are easier to write and read, making script maintenance less cumbersome.

  • Web-based Configuration: Fish includes a web interface that allows you to configure it from your browser—something unique that no other shell offers. This makes tweaking Fish’s behavior and appearance easier for users who prefer graphical interfaces over text files.

Switching to Fish

Fish can be installed on most systems with a simple package manager command. For example, on macOS, you can use Homebrew:

$ brew install fish

And on Ubuntu systems:

$ sudo apt install fish

To make Fish your default shell, you can use the chsh command:

$ chsh -s /usr/local/bin/fish  # The path to Fish might differ based on your installation

Integrating Fish into Your Workflow

Transitioning to Fish can be straightforward due to its intelligent design. It reads and executes commands from ~/.config/fish/, similar to Bash’s .bashrc. You can start by adding custom functions or aliases into this file.

Fish is particularly useful for developers who value a rich, straightforward, and interactive command line experience. Its syntax and features promote efficiency and ease of use, potentially making your command line tasks faster and more enjoyable.

For those interested in exploring the power of Fish or wanting a break from the more traditional Bash shell, Fish offers a refreshing and powerful alternative.

Anyway, choose Fish cuz it’s cool.


You may be interested in my dotfiles.

Code Review Guide

Code review is not just a duty to help maintain code quality; it’s also a powerful learning tool. Regularly reviewing code helps you discover new techniques and reinforces best practices. Therefore, it’s crucial to approach code reviews diligently and provide constructive, honest feedback.

Core Principles of Effective Code Reviews

Good code should be clear, clean, and efficient. Here are some questions to guide your review:

  1. Clarity: Is the code easy to understand at first glance? Can you discern the purpose of each line without extensive investigation?
  2. Standards Compliance: Does the code adhere to established coding standards and guidelines? (Refer to our Code Style Guide).
  3. Redundancy: Is there any code duplicated more than twice?
  4. Function Length: Are there overly long functions or methods that could be refactored to reduce complexity?
  5. Efficiency: Do you notice any inefficiencies? Could any parts of the code be optimized for better performance?

Detailed Code Review Checklist

Use this checklist to ensure comprehensive reviews. These items encompass best practices derived from various resources:

Best Practices

  • Avoid hard-coding values—use constants and variables.
  • Comments should explain why the code exists in its current form, detailing any temporary or complex logic.
  • Handle potential errors using try/catch blocks or other exception handling methods.
  • Prefer fewer conditional (if/else) blocks.
  • Minimize nested loops unless necessary.
  • Use early exits (like break in loops or return in functions) to reduce nesting.
  • Utilize existing frameworks and libraries that offer the needed functionality instead of custom solutions.
  • Credit any external code sources integrated into the application.


  • Ensure the code is self-explanatory.
  • Use descriptive names for variables, functions, and classes.
  • Maintain a single responsibility principle for classes and functions.
  • Provide user feedback for operations that aren’t instantaneous.


  • Maintain proper use of whitespace and ensure code blocks are easily distinguishable.
  • Follow the designated style guide.
  • Organize imports and constant declarations at the beginning of files.
  • Remove any code that is commented out to keep the codebase clean.

Efficiency and Reusability

  • Avoid repeating the same code across the project.
  • For variable data or settings, use hooks like command-line arguments to facilitate adjustments without modifying the code.
  • Choose the most efficient data structures and algorithms.
  • Ensure the code runs within a reasonable time frame given the context.
  • For code involving randomness, provide mechanisms to set and document the seed for reproducibility.

Code Style Guidelines

  • Python: Follow the PEP 8 style guide.
  • R: Adhere to Google’s R Style Guide.
  • Utilize linters during development to ensure consistent styling. Adjust maximum line lengths based on team preferences, documented in a project-specific .editorconfig file, to maintain consistency across various editors.

Additional Resources

For more insights into the value of code reviews and how to enhance their effectiveness, refer to these articles:

Engaging in thorough and thoughtful code reviews strengthens the codebase and builds a collaborative culture that values quality and continuous improvement.


Here is a list of the contributors who have helped improving The Art of Lazy Programming. Big.

If you feel you’re missing from this list, feel free to add yourself in a PR.


All the content in this course, including the website source code, lecture notes, exercises, and lecture videos is licensed under Attribution-NonCommercial-ShareAlike 4.0 International CC BY-NC-SA 4.0.

This means that you are free to:

  • Share — copy and redistribute the material in any medium or format
  • Adapt — remix, transform, and build upon the material

Under the following terms:

  • Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
  • NonCommercial — You may not use the material for commercial purposes.
  • ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.

This is a human-readable summary of (and not a substitute for) the license.

Contribution guidelines

You can submit corrections and suggestions to the course material by submitting issues and pull requests on our GitHub repo. Remember to add yourself to contributions.

Translation guidelines

You are free to translate the lecture notes and exercises as long as you follow the license terms. If your translation mirrors the course structure, please contact us so we can link your translated version from our page.