freedzhost.cloud

TSSR module 3: system administration and services

Level BeginnerEstimated time 14 hRead first TSSR module 2: networks, the heart of the jobA word you don't know? Glossary

Fourteen sessions on the services a technician installs, troubleshoots and explains: the web, remote access, mail, the directory, file sharing, printing, backup, monitoring, and the scripts that save you doing the same thing twice. The module ends with a mini-project between your two VMs.

For the two VMs to see each other, put them on the same VirtualBox "NAT Network" (day 13). Note the Debian VM's address with ip a: in the commands below it is written <debian-ip>.

Day 29 · 01/12 — HTTP, HTTPS: requests, status codes, TLS

Goal: read an HTTP request and response, and recognise the common status codes.

Theory 1/2: requests and responses

Tim Berners-Lee invented the Web at CERN in 1989-1991: pages in HTML, addresses (URLs) and a protocol, HTTP. The client sends a request: a method (GET to read, POST to send, also PUT, DELETE, HEAD), a path, headers (Host, User-Agent…). The server returns a response: a status code, headers, a body. Codes by family:

  • 2xx success: 200 OK;
  • 3xx redirection: 301 moved permanently, 302 temporarily;
  • 4xx client error: 401 authentication required, 403 forbidden, 404 not found;
  • 5xx server error: 500 internal error, 502 bad gateway (the proxy got no valid answer from the server behind it), 503 unavailable.

Which code does a server return for a page that does not exist?

Answer

404 Not Found.

A 503 code means…

  1. a client error
  2. an unavailable server
  3. a redirection
Answer

An unavailable server: the 5xx family is on the server side.

Theory 2/2: HTTPS and TLS

HTTPS is HTTP inside a TLS tunnel, on port 443 instead of 80. TLS encrypts the exchange and proves the server's identity with a certificate, signed by a certificate authority the browser knows. TLS succeeded SSL; the current version, TLS 1.3, dates from 2018 (RFC 8446). Since Let's Encrypt (2015), certificates are free and automatic.

Default port of HTTPS?

Answer

443 (HTTP: 80).

Practice (30 min)

curl -I https://www.debian.org            # headers only: 200?
curl -I http://www.debian.org             # 301 to https? Read the Location header
curl -I https://www.debian.org/page-that-does-not-exist   # 404
curl -v https://www.debian.org -o /dev/null  # the TLS handshake, then the request

In the curl -v output, find the TLS version, the certificate's issuer and its expiry date. Try two other sites and note the codes you get.

Recap (10 min)

Recite the five code families with one example each. Explain in one sentence what TLS adds.

Day 30 · 02/12 — SSH versus Telnet, public and private keys

Goal: connect by SSH from the Windows VM to the Debian VM, first with a password, then with a key.

Theory 1/2: why SSH

Telnet (RFC 854, 1983, port 23) opens a remote console, but everything travels in clear, password included: anyone on the path can read it. SSH, created by Tatu Ylönen in 1995 after a password-sniffing attack at his university, encrypts the session (port 22). OpenSSH, from the OpenBSD project in 1999, is the most widespread implementation; Windows 10 and 11 ship its client.

SSH's port?

Answer

22. Telnet: 23.

Theory 2/2: keys

A key pair is a private key, which never leaves your machine, and a public key, which you put on the server in ~/.ssh/authorized_keys. At login the server sets a challenge only the private key can sign: no secret crosses the network. Protect the private key with a passphrase. On the first connection SSH shows the server's fingerprint: check it, then it is kept in known_hosts.

Which key do you put on the server?

  1. The private key
  2. The public key
  3. Both
Answer

The public one. The private one never leaves your workstation.

Practice (30 min)

  1. In the Debian VM: systemctl status ssh (installed on day 6; otherwise sudo apt install openssh-server). Note its address: ip a.
  2. In the Windows VM, PowerShell: ssh <user>@<debian-ip>. Accept the fingerprint, enter the password, type hostname, then exit.
  3. Still on Windows: ssh-keygen -t ed25519 (accept the location, give a passphrase).
  4. Copy the public key: type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh <user>@<debian-ip> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys".
  5. Connect again: the key's passphrase is asked for, no longer the account password.

Recap (10 min)

Three lines: Telnet's flaw, each key's role, what the fingerprint is for. Redo the connection without notes.

Day 31 · 03/12 — Mail: SMTP, POP3, IMAP and their ports

Goal: draw the journey of an e-mail and assign each protocol to its step.

Theory (20 min)

  • SMTP (RFC 821 in 1982, today RFC 5321) sends: from the mail client to its server, then server to server. Ports: 25 between servers, 587 for submission by an authenticated client (STARTTLS), 465 for submission encrypted from the start.
  • POP3 (port 110, or 995 encrypted) retrieves: it downloads the messages and, by default, removes them from the server. Fine for a single device.
  • IMAP (port 143, or 993 encrypted) reads in place: messages and folders stay on the server, in sync across every device. The usual choice today.

The journey: Alice's client submits the message to her server over SMTP; that server looks up the MX record of the recipient's domain in DNS, then delivers over SMTP to Bruno's server; Bruno reads it over IMAP or POP3. SPF, DKIM and DMARC, published in DNS, help prove that a server may send for a domain.

Which protocol keeps messages on the server and syncs all your devices?

  1. SMTP
  2. POP3
  3. IMAP
Answer

IMAP. SMTP sends, POP3 downloads.

Port of encrypted IMAP (IMAPS)?

Answer

993.

How does Alice's server know where to deliver a message for another domain?

  1. From the domain's A record
  2. From the domain's MX record
  3. Through ARP
Answer

From the MX record.

Practice (30 min)

  1. Draw the journey of an e-mail from Alice (domain A) to Bruno (domain B): four actors (two clients, two servers), DNS, each arrow with its protocol and port.
  2. Check the DNS part for real: dig debian.org MX +short, then dig debian.org TXT +short and look for an SPF record (v=spf1; not every domain publishes one).
  3. In your own mail client, find the configured servers and ports and note them.

Recap (10 min)

Recite the three protocols, their role and their ports, plain and encrypted.

Day 32 · 04/12 — Web server: Apache or Nginx

Goal: serve a personal page from the Debian VM and open it from Windows.

Theory (20 min)

A web server listens on ports 80 and 443 and returns files, or passes the request on to an application. The two most widespread are free software: Apache HTTP Server (1995, configured by files and modules, per-directory .htaccess) and nginx (Igor Sysoev, 2004, built for many simultaneous connections with little memory, widely used as a reverse proxy). On Debian, nginx serves /var/www/html by default; its configuration is in /etc/nginx/, one file per site in sites-available, enabled by a link in sites-enabled.

On Debian, where does nginx look for the default page?

  1. /var/www/html
  2. /etc/nginx/html
  3. /srv/www
Answer

/var/www/html.

Which command checks nginx's configuration before reloading?

Answer

sudo nginx -t, then sudo systemctl reload nginx.

Practice (30 min)

  1. nginx has been installed since day 9; otherwise sudo apt install nginx.
  2. Write your page:
    sudo tee /var/www/html/index.html >/dev/null <<'EOF'
    <!doctype html>
    <html lang="en"><meta charset="utf-8"><title>TSSR lab</title>
    <h1>My Debian VM serves this page</h1>
    </html>
    EOF
  3. Test locally: curl -I http://localhost (200?) and curl http://localhost.
  4. From the Windows VM, open http://<debian-ip>/ in the browser.
  5. Read the logs: sudo tail -n 5 /var/log/nginx/access.log. Windows' visit is there.

Recap (10 min)

Three lines: where the page is, where the configuration is, where the logs are. Replace the page with another without notes.

Day 33 · 05/12 — Directory: Active Directory basics

Goal: understand domain, controller, organisational units and group policies, and draw a fictitious directory.

Theory 1/2: the directory

In a company, accounts are not created machine by machine: a directory centralises users, groups and computers. Active Directory (AD), which came with Windows 2000 Server, is Microsoft's directory, queried over LDAP and authenticated with Kerberos. It relies on DNS for workstations to find their controllers.

  • Domain: the administrative boundary, named like a DNS domain (lab.example).
  • Domain controller (DC): the server that hosts the directory and authenticates. You run at least two.
  • Forest and tree: a set of domains that trust one another.

Which service does AD rely on for workstations to find their controller?

  1. DHCP
  2. DNS
  3. SMTP
Answer

DNS.

Theory 2/2: OUs and GPOs

An organisational unit (OU) is a folder of the directory: accounts and computers go in it, often by site or department. Administration is delegated there, and group policies (GPOs) are linked to it: settings applied automatically to the OU's accounts and machines (wallpaper, network drive, password rules, software install). GPOs apply in the order local, site, domain, OU ("LSDOU"): the last one applied wins in a conflict. A good practice: rights go to groups, never straight to accounts.

You want every Accounts workstation to map the accounts network drive. You link a GPO…

  1. to the whole domain
  2. to each account one by one
  3. to the Accounts OU
Answer

To the Accounts OU: it only touches what it contains.

Practice (30 min)

  1. Invent a 30-person company on two sites, Lyon and Nantes, with Management, Accounts and Workshop departments.
  2. Draw the AD tree of the domain sme.example: one OU per site, Users and Computers sub-OUs per department, a Groups OU.
  3. Place five fictitious accounts, three groups (GG_Accounts…), two GPOs (accounts network drive, screen lock after 10 minutes) and show where each is linked.
  4. To go further later: Windows Server also has a free evaluation, to build a real controller on day 56.

Recap (10 min)

Define domain, DC, OU and GPO in one line each from memory, and the LSDOU order.

Day 34 · 06/12 — File sharing: SMB and network drives

Goal: share a folder from the Debian VM and map it as a network drive on Windows.

Theory (20 min)

SMB (Server Message Block), created at IBM in the 1980s then developed by Microsoft, is Windows' file and printer sharing protocol, on TCP port 445. SMBv1 is obsolete and dangerous (the WannaCry ransomware exploited it in 2017): use SMB 2 or 3. Samba, written by Andrew Tridgell from 1992, implements SMB on Linux. On Windows a share is written \\server\share (UNC path) and mapped to a drive letter. Two layers of rights apply: the share's and the file system's; the more restrictive wins. On Linux, the historical equivalent is NFS.

SMB's TCP port?

Answer

445.

The share grants Modify, the file system Read only. What can the user do?

  1. Read only
  2. Modify
Answer

Read only: the more restrictive of the two wins.

Practice (30 min)

  1. In the Debian VM: sudo apt install samba.
  2. Create the folder and a Samba account (the Samba password is separate from the system one):
    sudo mkdir -p /srv/share/common
    sudo chown alice:accounts /srv/share/common
    sudo chmod 770 /srv/share/common
    sudo smbpasswd -a alice
  3. At the end of /etc/samba/smb.conf:
    [common]
       path = /srv/share/common
       valid users = @accounts
       read only = no
  4. testparm to check, then sudo systemctl restart smbd.
  5. On Windows: File Explorer → This PC → Map network drive, folder \\<debian-ip>\common, alice's credentials. Or on the command line: net use Z: \\<debian-ip>\common /user:alice.
  6. Create a file from Windows, check that it shows up in /srv/share/common with ls -l.

Recap (10 min)

Three lines: SMB, Samba and the UNC path; the two layers of rights; why not SMBv1.

Day 35 · 07/12 — Network printing and print queues

Goal: understand the path of a print job and manage a queue.

Theory (20 min)

A print job goes through a spooler: the job is queued, then sent to the printer when it is free. On Windows that is the Print Spooler service (seen on day 5); on Linux and macOS it is CUPS. Two set-ups:

  • each workstation prints directly to the printer, by its IP address;
  • a print server shares the printers: one queue, drivers deployed from the server, a GPO to install them on workstations.

Common protocols: RAW port 9100 (the job is sent as is), IPP (port 631, used by CUPS and recent printers, the basis of driverless printing), LPD (port 515, old). The most frequent fix: a stuck job holding the whole queue. Delete it; if it resists, stop the spooler, empty its queue, start it again.

A stuck print job holds the whole queue. First action?

  1. Reinstall the driver
  2. Delete the stuck job from the queue
  3. Change the printer's IP address
Answer

Delete the job; restart the spooler if needed.

IPP's port?

Answer

631.

Practice (30 min)

  1. In the Debian VM: sudo apt install cups printer-driver-cups-pdf. CUPS creates a virtual PDF printer.
  2. lpstat -p -d: find the printer. Print a file: lp -d PDF /etc/hostname (the exact name comes from lpstat). The PDF lands in the PDF folder of your home directory.
  3. Pause the printer (sudo cupsdisable PDF), send two jobs, look at the queue with lpstat -o, delete one with cancel, re-enable it (sudo cupsenable PDF).
  4. On Windows: Settings → Printers & scanners → "Microsoft Print to PDF"; print a page, open the queue, pause a job then delete it.

Recap (10 min)

Three lines: what a spooler does, direct versus print server, the procedure for a stuck queue.

Day 36 · 08/12 — Backup: full, incremental, differential, DRP

Goal: choose a backup strategy and write a plan for a small business.

Theory 1/2: the three types

  • Full: everything, every time. Simple restore, but long and bulky.
  • Incremental: what changed since the last backup of any kind. Fast and light; restoring needs the full one then every incremental in order.
  • Differential: what changed since the last full one. Grows every day; restoring needs the full one plus the latest differential.

Full on Sunday, differentials after that. Failure on Thursday: what do you restore?

  1. The full one and every differential
  2. The latest differential alone
  3. The full one, then Wednesday's differential
Answer

The full one, then the latest differential (Wednesday night).

Theory 2/2: RPO, RTO, DRP

Two figures set a strategy: the RPO (maximum acceptable data loss, for example one day) and the RTO (maximum acceptable downtime, for example four hours). The DRP (disaster recovery plan) describes how to restart after a disaster; the BCP (business continuity plan) aims not to stop at all. A backup never restored is only a hope: test restores regularly. Day 12's 3-2-1 rule applies, with an offline or immutable copy against ransomware.

"We accept losing at most one hour of data entry." That figure is the…

  1. RPO
  2. RTO
Answer

The RPO, the acceptable data loss. The RTO is the acceptable downtime.

Practice (30 min)

Backup plan for a 10-person office (a file server, an accounting database, workstations):

  1. Inventory: what to back up, how much, how critical.
  2. RPO and RTO for each kind of data.
  3. Schedule: which types, which days, which retention (how many versions are kept).
  4. Media and locations, applying 3-2-1.
  5. Restore test: what, when, by whom, how it is proven.

Recap (10 min)

Three lines: incremental versus differential, RPO versus RTO, why test restores.

Day 37 · 09/12 — Monitoring: SNMP, logs, metrics

Goal: know what to monitor, with what, and read a Linux system's logs.

Theory (20 min)

Monitoring means seeing a failure before the users do. Three sources:

  • Metrics: figures over time (processor, memory, disk, bandwidth, response time), with alert thresholds.
  • Logs: timestamped events. On Linux, journald (systemd) and the files in /var/log; the syslog protocol gathers them on a server. On Windows, Event Viewer (eventvwr.msc).
  • SNMP (Simple Network Management Protocol, RFC 1157 in 1990; UDP port 161 for queries, 162 for "trap" alerts): the monitor queries network devices, which expose their values in a database called the MIB. Versions 1 and 2c authenticate with a mere "community" string in clear; SNMPv3 adds authentication and encryption.

Common free tools: Zabbix, Nagios and its offshoots, Prometheus with Grafana for dashboards.

Which SNMP version encrypts and authenticates?

  1. v1
  2. v2c
  3. v3
Answer

SNMPv3.

Which command shows the logs of the ssh service only?

Answer

journalctl -u ssh.

Practice (30 min)

journalctl -b                  # since the last boot
journalctl -p err -b           # errors only
journalctl -u ssh --since today
sudo journalctl -f             # live (Ctrl+C to leave)
df -h ; free -h ; uptime       # three basic metrics

While journalctl -f runs, connect by SSH from Windows with a wrong password: watch the failure get logged. Note the exact line: that is what a tool like fail2ban watches for.

Recap (10 min)

Three lines: metrics versus logs, what SNMP does, three journalctl options.

Day 38 · 10/12 — Bash scripting 1: variables, conditions, loops

Goal: write a script that checks whether a list of machines answers.

Theory 1/2: variables and conditions

Bash (Brian Fox, 1989, for the GNU project) is the default shell of many distributions. A script is a text file starting with #!/bin/bash, made executable with chmod +x.

  • Variable: host="debian.org" (no spaces around =), read as "$host". Always in double quotes.
  • Arguments: $1, $2…; their count, $#.
  • Exit code: every command returns 0 on success, something else otherwise; $? holds it.
  • Condition: if command; then … else … fi, or a test: if [ "$#" -eq 0 ]; then ….

Which exit code means a command succeeded?

Answer

0. Any other value signals an error.

Which of these assignments is valid bash?

  1. host = "debian.org"
  2. host="debian.org"
  3. $host="debian.org"
Answer

host="debian.org": no spaces, no $ when assigning.

Theory 2/2: loops

for h in a b c; do … done walks a list; while read -r line; do … done < file reads a file line by line. Before running a script, bash -n script.sh checks its syntax; the shellcheck tool (package of the same name) flags the usual mistakes.

Practice (30 min)

#!/bin/bash
# check-hosts.sh: tell which hosts answer a ping.
if [ "$#" -eq 0 ]; then
  echo "usage: $0 host..." >&2
  exit 2
fi
for h in "$@"; do
  if ping -c 1 -W 2 "$h" >/dev/null 2>&1; then
    echo "OK    $h"
  else
    echo "DOWN  $h"
  fi
done
  1. Type this script (do not paste it) into ~/check-hosts.sh, chmod +x ~/check-hosts.sh.
  2. Run ./check-hosts.sh debian.org 192.0.2.1 localhost: 192.0.2.1, a documentation address, will not answer.
  3. Improve it: count the DOWN machines and end with exit 1 if there is at least one.

Recap (10 min)

Rewrite the script from memory, then run it through bash -n.

Day 39 · 11/12 — Bash scripting 2: automating, cron

Goal: write five small useful scripts, including a backup scheduled by cron.

Theory (20 min)

cron runs commands at set times. crontab -e edits the user's table; each line has five time fields then the command:

# minute hour day-of-month month day-of-week  command
30 2 * * *   /usr/local/bin/backup-dir.sh   # every night at 2:30
*/15 * * * * /usr/local/bin/check-hosts.sh debian.org

Under cron the environment is minimal: use absolute paths and send the output to a log. On a systemd machine, timers are the modern alternative. Backups rely on tar (archive, -z to compress) or rsync (incremental copy).

What does 0 7 * * 1 mean?

  1. Every Monday at 7:00
  2. Every day at 0:07
  3. The 7th of every month
Answer

Minute 0, hour 7, any day of the month, any month, on Monday (1).

Which command edits your cron table?

Answer

crontab -e; crontab -l lists it.

Practice (30 min)

  1. The backup script:
    #!/bin/bash
    # backup-dir.sh: archive a directory into a dated tarball, keep the last 7.
    set -eu
    src=${1:?usage: backup-dir.sh directory}
    dest=/var/backups/lab
    mkdir -p "$dest"
    tar -czf "$dest/$(basename "$src")-$(date +%F-%H%M).tar.gz" -C "$(dirname "$src")" "$(basename "$src")"
    ls -1t "$dest"/*.tar.gz | tail -n +8 | xargs -r rm --
  2. Install it: sudo install -m 755 backup-dir.sh /usr/local/bin/, test it by hand on /srv/share/common, then list /var/backups/lab.
  3. Schedule it in root's crontab (sudo crontab -e) every 5 minutes for the test, check that an archive appears, then set it back to once a night.
  4. Restore an archive into /tmp (tar -xzf … -C /tmp): a backup is proven by a restore.
  5. Four more short scripts, on your own: free disk space with an alert under 20%; the list of human accounts (UID ≥ 1000 in /etc/passwd); the five largest files of a folder; the number of refused SSH logins today (building on day 37).

Recap (10 min)

Write from memory the cron line "every night at 2:30" and the tar command that creates a compressed archive.

Day 40 · 12/12 — PowerShell: the bash equivalents

Goal: do on Windows, in PowerShell, what you already know how to do in bash.

Theory (20 min)

PowerShell, designed by Jeffrey Snover at Microsoft and released in 2006, rests on one idea: commands, called cmdlets, pass objects, not text. So you filter by property instead of cutting lines. Names follow a Verb-Noun pattern: Get-Process, Stop-Service. PowerShell has been free and cross-platform since 2016 (PowerShell 7 today); Windows also ships the older Windows PowerShell 5.1.

bashPowerShell
ls, cd, pwdGet-ChildItem, Set-Location, Get-Location (the aliases ls, cd, pwd exist)
cat, grepGet-Content, Select-String
ps, killGet-Process, Stop-Process
systemctl status|start|stopGet-Service, Start-Service, Stop-Service
manGet-Help; and Get-Command to find a cmdlet
ping, ip aTest-Connection, Get-NetIPAddress

Which cmdlet lists the services?

Answer

Get-Service.

The basic difference between a bash pipe and a PowerShell pipe?

  1. There is none
  2. PowerShell passes objects, bash passes text
  3. PowerShell is slower
Answer

PowerShell passes objects with their properties.

Practice (30 min)

Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
Get-Service | Where-Object Status -eq 'Running' | Measure-Object
Get-Service Spooler
Restart-Service Spooler          # in an administrator console
Get-ChildItem C:\Windows -File | Sort-Object Length -Descending | Select-Object -First 5 Name, Length
Test-Connection debian.org -Count 2
Get-NetIPAddress -AddressFamily IPv4
Get-Help Get-Service -Examples

Then rewrite day 38's check-hosts.sh in PowerShell with foreach and Test-Connection -Quiet. If running scripts is blocked, read Get-Help about_Execution_Policies before changing anything.

Recap (10 min)

Copy the correspondence table from memory.

Day 41 · 13/12 — Cloud and containers: IaaS, PaaS, SaaS, Docker

Goal: place the three cloud models and understand what a container is.

Theory 1/2: the three models

NIST set the reference definition of cloud computing in 2011 (publication SP 800-145). It distinguishes three service models, by what the provider manages for you:

  • IaaS (infrastructure): you rent virtual machines, storage, network; you manage the system and what runs on it.
  • PaaS (platform): you deploy your application, the provider manages the servers and the system.
  • SaaS (software): you use a ready-made application in the browser; you only manage your data and accounts.

The same publication distinguishes the deployment models: public, private, hybrid and community cloud.

An online mailbox used in the browser, with nothing installed, is…

  1. IaaS
  2. PaaS
  3. SaaS
Answer

SaaS.

Theory 2/2: containers

A VM carries a whole operating system on virtual hardware. A container shares the host's kernel and isolates only the application and its dependencies (with the Linux kernel's namespaces and cgroups): it starts in a second and weighs far less. Docker, unveiled in 2013, made it simple: an image is a read-only template, a container is a running instance of it, a Dockerfile describes how to build the image, a registry (Docker Hub) distributes them.

What does a container share with its host, unlike a VM?

  1. Its IP address
  2. The kernel
  3. Nothing
Answer

The host system's kernel.

Practice (30 min)

  1. Draw the three models as three columns of layers (network, storage, servers, virtualisation, system, runtime, application, data) and colour what the customer manages in each.
  2. Draw a VM and a container side by side: where is the kernel?
  3. First reading on Docker: the "Get started" page of the official documentation (docs.docker.com). Write the definitions of image, container and registry in your own words.
  4. Optional, if the VM has room: install Docker following the official procedure for Debian, then sudo docker run --rm hello-world.

Recap (10 min)

Three lines: IaaS, PaaS and SaaS with one example each; VM versus container; image versus container.

Day 42 · 14/12 — Module 3 review: the mini-project

Goal: a Debian VM serving a web page reachable from Windows by its IP address, documented in ten lines.

Theory (20 min): documenting

An undocumented installation has to be redone from memory on the day it breaks. A good short document says: what the system does, where it is (address, name), how it is installed (packages, files changed), how to check it works, how to restart it, where its logs are, what is left to do. It is written for someone else: your colleague, or you in six months.

Who is technical documentation written for?

  1. For yourself, today
  2. For someone who does not know the installation
  3. For the trainer only
Answer

For someone who does not know it, including you later.

Practice (30 min)

  1. Restore the Debian VM's clean snapshot (day 13), or start from a fresh VM.
  2. Without notes: address checked, nginx installed and enabled at boot, personal page in place, local curl test.
  3. From Windows: ping <debian-ip>, then the page in the browser, then curl.exe -I http://<debian-ip>/.
  4. Write the documentation in ten lines: role, address, system, packages, page file, test command, restart, logs, SSH access, limits.

Recap (10 min)

Reread your document as if you were discovering it: is a step missing to redo the project? Add it.

Sources

Found this useful? Tell us what to measure next.

Comments

No account, no tracker: a comment is read by a human before it appears.