# Introduction

Welcome to my personal wiki

In this space, I will be mostly adding stuff that I find useful.&#x20;

Most of it will probably be related to, but not limited to, software development, so expect cheat sheets, tutorials, etc.

An experiment inspired by [Nikita Voloboev's Personal Wiki](https://wiki.nikitavoloboev.xyz/).


# Raspberry

Here I show some of the configurations of my Raspberry Pi.&#x20;


# OS Installation

Install Raspberry Pi OS

There are different operating systems available for Raspberry Pi. I usually choose Raspberry Pi OS, which was formerly known as Raspbian.

### Requirements

To install the OS, we need:

* Raspberry Pi
* Memory SD card
* USB cable

### Raspberry Pi OS

Raspberry provides a software assistant to download and burn the chosen OS into your SD card. You can download it from the [official website](https://www.raspberrypi.org/software/).

![](https://3843519048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MS0GkbkSOa0mBDFFjNz%2F-MS4HgO-PDWWvsnY68NB%2F-MS4Jlg728b7qNNNnDdA%2Fimage.png?alt=media\&token=e6bf6c2a-99fe-4d17-b041-56221aef5504)

### Install

Connect the Raspberry Pi to the computer and launch the Raspberry Pi manager. Choose the operating system, the SD card, and click on *Write*. This process might take few minutes.

If everything succeeds, you’ll see the following message:

![](https://cdn-images-1.medium.com/max/1600/1*ToV6Z-PlWXqgUZH11SqtWQ.png)

If not, you may want to try to select the *Erase* option from the *Operating System* options in the first figure.

{% hint style="info" %}
More info in the [Raspberry Pi blog](https://www.raspberrypi.org/blog/raspberry-pi-imager-imaging-utility/).
{% endhint %}


# Enable SSH and first access

By default, access via ssh is not enabled on your Raspberry. To change this, insert the SD card into your computer’s card reader, go to the root of the **boot** partition and place an empty file with the name **ssh**.&#x20;

```bash
touch ssh
```

Once this is done, insert the SD card back into the Raspberry and connect it to your LAN using an Ethernet cable.

## First access

Now, time to ssh into the raspberry for the first time! To do so, we need the private IP of the Raspberry, which you can find looking into your local network in the router preferences or using tools such as **Nmap**. Once known, you can ssh using the default credentials:

| field      | value     |
| ---------- | --------- |
| `user`     | pi        |
| `password` | raspberry |

{% hint style="info" %}
[Nmap](https://nmap.org/) is a free and open-source network scanner created by Gordon Lyo.
{% endhint %}

```bash
ssh pi@${PRIVATE_IP}
```

Once connected, [look for updates](https://howchoo.com/pi/update-raspberry-pi-raspbian).

```bash
sudo apt-get update
sudo apt-get upgrade --yes
```

Finally, restart your raspberry

```bash
sudo reboot
```


# SSH configuration

## Set static IP

#### See what's managing eth0

Run

```
systemctl is-active NetworkManager
systemctl is-active systemd-networkd
nmcli dev status 2>/dev/null || true
```

#### If NetworkManager is active

1. Get the connection name for eth0:

```
nmcli -g NAME,DEVICE con show --active
```

2. Set static IP (replace CONN\_NAME with the name you got):

```
sudo nmcli con mod "CONN_NAME" ipv4.addresses 192.168.1.101/24
sudo nmcli con mod "CONN_NAME" ipv4.gateway 192.168.1.1
sudo nmcli con mod "CONN_NAME" ipv4.dns "192.168.1.1 1.1.1.1"
sudo nmcli con mod "CONN_NAME" ipv4.method manual
sudo nmcli con down "CONN_NAME" && sudo nmcli con up "CONN_NAME"
```

3. Verify

```
ip -4 addr show dev eth0
ip route | grep default
```

You want:

* inet 192.168.1.101/24
* default via 192.168.1.1 dev eth0 (may or may not still say proto dhcp, but the key is the src becomes .101 and the address is static)

#### If systemd-networkd is active

Open the file `/etc/dhcpcd.conf` and place the following lines of code, which configures the connection using the `eth0` (ethernet) interface:

{% code title="/etc/dhcpcd.conf" %}

```
# Example static IP configuration:
interface eth0
static ip_address=192.168.1.X/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8 8.8.4.4
```

{% endcode %}

In the example above, we have used `192.168.1.X/24` as the static private IP and `192.168.1.1` is the IP of our router (a.k.a. gateway, check it using `router -n` command).

Finally, restart the device

```
sudo reboot
```

{% hint style="info" %}

* [How to Setup a Raspberry Pi Static IP Address](https://pimylifeup.com/raspberry-pi-static-ip-address/) (Post)
* [How to assign static IP address to Raspberry Pi](https://www.youtube.com/watch?v=LCJtUbRlIXE) (Video)
  {% endhint %}

## Change ssh port

A good practice to increase security is to change the default ssh port (22) to a different one (higher than 1000, lower than 65535). Open the ssh configuration (file /etc/ssh/sshd\_config) and uncomment the line called “Port 22” and change it to&#x20;

{% code title="/etc/ssh/sshd\_config" %}

```
Port [SSH_NEW_PORT]
```

{% endcode %}

Finally, restart ssh service

```
sudo service ssh restart
```

Now, to access the raspberry type:

```
$ ssh -p [SSH_NEW_PORT] pi@192.168.1.X
```

{% hint style="info" %}
[How to change your SSH Port on the Raspberry Pi](http://kamilslab.com/2016/12/10/how-to-change-your-ssh-port-on-the-raspberry-pi/)
{% endhint %}


# Change default credentials

## Password

You can leave the username as it comes, i.e. **pi**. However, I will obviously change the password. This can be done with the command `passwd`.

{% tabs %}
{% tab title="Shell" %}

```
passwd
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
[Raspberry Pi: Default Password & How To Change](https://www.shellhacks.com/raspberry-pi-default-password-how-to-change/), *shellhacks.com, May 7th 2020*
{% endhint %}

## Hostname

Use the system tool `raspi-config` to edit the hostname.

{% tabs %}
{% tab title="Shell" %}

```shell-session
raspi-config
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
[*How to Change Your Raspberry Pi's Hostname*](https://www.tomshardware.com/how-to/raspberry-pi-change-hostname), tomshardware.com, May 1st 2020
{% endhint %}


# Home DNS

[**Home**\
*Network-wide protection Instead of browser plugins or other software on each computer, install Pi-hole in one place and…*&#x70;i-hole.net](https://pi-hole.net/)

[**Complete Pi Hole setup guide: Ad-free better internet in 15 minutes**\
*Want to have a better online experience without advertisements and sneaky tracking codes that invade your privacy and…*&#x77;ww.smarthomebeginner.com](https://www.smarthomebeginner.com/pi-hole-setup-guide/)[**How to setup Pi-Hole on the** ](https://pimylifeup.com/raspberry-pi-pi-hole/)

[**Raspberry Pi**\
*In this Raspberry tutorial, we will be setting up a network-wide ad blocker called Pi-hole. Pi-hole works by acting as…*&#x70;imylifeup.com](https://pimylifeup.com/raspberry-pi-pi-hole/)


# WiFi USB

In this section, we connect an external WiFi receiver to enable a wireless connection.

For this step we need internet connection. Make sure that the raspberry is connected with an ethernet cable.

Check with `ifconfig` available connectons

```
$ ifconfig -a
...
wlan0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 
       ether b0:a7:b9:ce:d3:58 txqueuelen 1000 (Ethernet)
       RX packets 0 bytes 0 (0.0 B)
       RX errors 0 dropped 0 overruns 0 frame 0
       TX packets 0 bytes 0 (0.0 B)
       TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```

We observe that there is no IP associated to `wlan0` interface. Let' change that. Run the following command and copy it to the clipboard.

```
$ wpa_passphrase [SSID] [SSID_PASSWORD]
```

where `SSID` and `SSID_PASSWORD` are the network name and password, respectively. Then open the file `wpa_supplicant.conf`&#x20;

```
$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
```

and paste the content at the end. Also, add four additonal fields. At the end you should have somethng like below:

{% code title="/etc/wpa\_supplicant/wpa\_supplicant.conf" %}

```
network={
        ssid=[SSID]
        psk=[SSID_PASSWORD_PSK]
        proto=RSN
        key_mgmt=WPA-PSK
        pairwise=CCMP
        group=CCMP
}
```

{% endcode %}

Finally, reboot the raspberry and it should connect to the network by default.

```
$ sudo reboot
```

{% hint style="info" %}
[*How to Set Up a USB Wi-Fi Adapter With the Raspberry Pi*](https://www.lifewire.com/usb-wifi-adapter-raspberry-pi-4058093)*,* lifewire.com, August 25th 2021
{% endhint %}

## Additionally

You can set a static IP this wirelessconnectin, just as you dit with the wire d connection in section [Set static IP](/home-setup/raspberry/untitled).


# Live cam

Configuration of a live cam.

Next, we want to configure a live cam connected to the Raspberry. With a cam, there can be multiple applications:

* 24h live stream of whatever. Exposing a port in the local network should suffice.
* Take a picture at a certain point of the day and save it. Then, timelapse can be done.

source:&#x20;

To use cv2:

* Create virtual environment `python3 -m venv venv`
* Activate it `. venv/bin/activate`
* Install cv2 `pip install opencv-python`
* Install extra libs required `sudo apt-get install libatlas-base-dev`
* Run following script

```python
import cv2
import time

cap = cv2.VideoCapture(0)
ret, frame = cap.read()

def takePicture():
    (grabbed, frame) = cap.read()
    showimg = frame
    # cv2.imshow('img1', showimg)  # display the captured image
    cv2.waitKey(2000)
    #time.sleep(1) # Wait 300 miliseconds
    image = 'test-image.png'
    cv2.imwrite(image, frame)
    cap.release()
    return image

print(takePicture())
```

Play with waitKey(\*) to let some seconds to focus light. Also, adjust cam.

{% hint style="info" %}
<https://github.com/opencv/opencv-python>

<https://raspberrypi-guide.github.io/electronics/using-usb-webcams>

<https://stackoverflow.com/questions/53347759/importerror-libcblas-so-3-cannot-open-shared-object-file-no-such-file-or-dire>

<https://gist.github.com/Luxato/384a7c8a6bfdeba09d54cb5bd6b2c9fb>
{% endhint %}


# ESP32

\[Work in Progress]

This all started because if connected via cable, we need a very long distance. This [comment](https://forums.raspberrypi.com/viewtopic.php?t=290748#p1759186), shed some light on the matter and pointed me to a different architecture:

* Power supply (solar)
* ESP32
* Moisture sensor &#x20;

{% hint style="info" %}
[Capacitive Soul Moisture Sensor with ESP8266/ESP32 & OLED Display](https://how2electronics.com/capacitive-soil-moisture-sensor-esp8266-esp32-oled-display/)

[Send data from ESP8266 or ESP32 to Raspberry Pi via MQTT](https://diyi0t.com/microcontroller-to-raspberry-pi-wifi-mqtt-communication/)

[Getting started with the ESP32 Development Board](https://randomnerdtutorials.com/getting-started-with-esp32/)

[Micropython](https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/)
{% endhint %}


# AD/DA

\[Work in Progress]

* Device: Waveshark Raspberry Pi High-Precision AD/DA Expansion Board

Doc:

* <https://www.waveshare.com/wiki/High-Precision_AD/DA_Board>

Requirements:

* Install bcm2835 stuff: <https://github.com/momenso/node-dht-sensor/issues/26#issuecomment-160486535>
* Copy [source code](https://www.waveshare.com/wiki/File:High-Precision-AD-DA-Board-Code.7z) to raspberry
* Go to bcm2835 and run `make; sudo ads1265_test`
* Python
  * Install spidev: `pip install git+https://github.com/doceme/py-spidev`
  * install RPi: `pip install RPi.GPIO`
  * Note: Need to [enable SPI](https://www.raspberrypi-spy.co.uk/2014/08/enabling-the-spi-interface-on-the-raspberry-pi/) (<https://www.takaitra.com/spi-device-raspberry-pi/>)


# Humidity sensors

\[Work in Progress]

calibrating: <http://chosiad.com/2020/05/18/calibrating-the-moisture-sensor-and-storing-the-configuration/>


# Remote access


# ssh

#### SSH change port

[**How to change SSH port on Centos 6, 7, and 8.**\
*Changing SSH Port will help to secure your Linux VPS server, here is ultimate guide how to secure linux vps server …*&#x6D;onovm.com](https://monovm.com/blog/how-to-change-ssh-port-on-centos/)

**Add to sshd configuration**

Go to the file

```
# nano /etc/ssh/sshd_config
```

and add line

```
Port <SSH_NEW_PORT>
```

**Configure SELinux**

```
# semanage port -a -t ssh_port_t -p tcp 50
```

**Configure Firewall**

```
# firewall-cmd --permanent --remove-service=ssh
success
# firewall-cmd --permanent --add-port=<SSH_NEW_PORT>/tcp
success
# firewall-cmd --reload
```

Restart sshd service

```
# systemctl restart sshd 
# systemctl status sshd.service
```

Remote access be like

```
# ssh -p <SSH_NEW_PORT> server@ip
```

#### SSH using keys

On your remote device follow these steps.

**Generate key**

[Comparison](https://gravitational.com/blog/comparing-ssh-keys/): TL;DR, use RSA 4096 or ed25519.

```
$ ssh-keygen -t ed25519
```

By default, will be stored at /home/user/.ssh/id\_ed25519

Generate a passphrase with [KeePassXC](https://keepassxc.org/) and use it as passphrase when it asks you for one.

**Add it to remote key (server)**

```
$ ssh-copy-id -p <PORT> -i ~/.ssh/id_ed25519 user@remote
```

This will add the public key (i.e. id\_ed25519.pub) to the the server file \~./.ssh/authorized\_keys

**Add passphrase to KeePassXC**

Follow this [tutorial,](https://www.techrepublic.com/article/how-to-integrate-ssh-key-authentication-into-keepassxc/) so you can add the passphrase for the generated key automatically to the ssh-agent whenever KeePassXC db is unlocked.

Now, passphrase won’t be asked when KeePassXC is unlocked.

**Disable ssh with password**

<https://linuxhandbook.com/ssh-disable-password-authentication/>\
Open file /etc/ssh/sshd\_config and set

```
PasswordAuthentication no
```

Next, restart ssh service

RHEL:

```
$ sudo service ssh restart
```

Arch:

a


# Turn on a remote computer

I have a machine that I use to do lot of work. However, I want to avoid having it on 24/7. Hence, sometiems I need to turn it on remotely to start working

#### Guide

To turn on your computer remotely, you need to be in the same network and then use the protocol "Wake-on-Lan." Read below for a step-by-step guide.

1. **Be in the same network**. I recommend having a Raspberry Pi on 24/7, which you can SSH into anytime. Alternatively, you can use a VPN to connect to your network (also via a Raspberry Pi).
2. **SSH into the Raspberry**
3. **Create a directory for managing this operation**. &#x20;

```bash
# use wake on lan
mkdir remote_on
```

4. **Find out the MAC address of your computer.** You can do it. Then save it in file `MAC_ADDR`:

```bash
# use wake on lan
cd remote_on
echo "..." > MAC_ADDR
```

5. **If not available, install a client to use Wake-on-Lan**. I use [etherwake](https://linux.die.net/man/8/ether-wake).
6. **Draft a script to do the job**

```bash
# use wake on lan
MAC_FILE="$(dirname "$0")/MAC_ADDR"
etherwake -i eth0 "$(cat "$MAC_FILE")"
```

7. Make the script executable

```bash
chmod +x /home/pi/remote_on/script.sh
```

8. Add an alias to your `.bashrc` like:

```bash
alias turnon='sudo /home/pi/remote_on/script.sh'
```

***

{% hint style="info" %}
[Main reference](https://serverfault.com/questions/266118/turn-on-a-linux-machine-remotely/266181#266181)

\
Wake on Lan:

* [Arch guide](https://wiki.archlinux.org/index.php/Wake-on-LAN#Enable_WoL_on_the_network_adapter) (**Note**: on TUF B550M ASUS bios ([manual](https://dlcdnets.asus.com/pub/ASUS/misc/Manual/PRIME_TUF_GAMING_B550_Series_BIOS_EM_WEB_EN.pdf), pg. 31), enable option “Power On By PCI-E”)
* [Problem solving](mailto:undefined)
  {% endhint %}


# Dynamic DNS

To be able to access your home network devices remotely, you need to know the public IP of your network. This is given by your ISP and changes dynamically.&#x20;

In this section, we will create a DNS alias that will map a given hostname to your up-to-date public IP. To this end, we will use [NOW-DNS](https://now-dns.com/).

## **Create DNS for your public IP**

* Go to [NOW-DNS](https://now-dns.com/) and register.
* Go to ***Manage Hostnames*** in the left navigation bar.
* Create your hostname. First, you need to click on ***Check Availability***, next it will ask you for your public IP. Note that NOW-DNS will auto-fill it, however, you easily check your IP [here](https://www.whatismyip.com/).

![NowDNS configurayion panel](https://cdn-images-1.medium.com/max/1600/1*jEfSCgHj66C2a95MsRNPKA.png)

* Once created, your hostname will appear on the DNS table.

![Registered DNS](https://cdn-images-1.medium.com/max/1600/1*baDiiGcxcIYmISz8F4DwoA.png)

## **Dynamically update the hostname**

As aforementioned, public IPs are dynamic, which means that they change from time to time (e.g. router reboot). Getting track of these changes is unfeasible, even more when you are abroad (as you would need to access your home network which in turn requires you to previously know the current public IP).&#x20;

To solve this, we simply **create a script that updates the NOW-DNS hostname** (using [NOW-DNS API](https://now-dns.com/?m=api)) and place it as a crone task on the raspberry.

### Create file with credentials

First, create a file called `/home/pi/crons/now-dns/credentials` with your NOW-DNS details using the following structure:

{% code title="/home/pi/crons/now-dns/credentials" %}

```
machine now-dns.com login [YOUR_MAIL] password [YOUR_PASSWORD]
```

{% endcode %}

After creating, modify the permissions so only you have access

```
chmod 600 /home/pi/crons/now-dns/credentials
```

{% hint style="info" %}

* [Is "curl -u username:password http://example.com" secure?, StackExchange](https://superuser.com/questions/919859/is-curl-u-usernamepassword-http-example-com-secure)
* [How to pass credentials to curk?, StackOverflow](https://stackoverflow.com/questions/32802667/how-to-pass-credentials-to-curl)
  {% endhint %}

### Automate hostname updates

To do this, we will create a local script, which runs periodically (using `crontab`). First, we create a script file.

{% code title="/home/pi/crons/now-dns/script.sh" %}

```
# Get current public IP
PUBLIC_IP=$(curl icanhazip.com)
NOW_DNS="lucas-example.2mydns.net"

# Update ip
curl --netrc-file /home/pi/crons/now-dns/credentials \
    https://now-dns.com/update?hostname=$NOW_DNS&myip=$PUBLIC_IP
```

{% endcode %}

Next, we add script execution to crontab. In our configuration, we set an every-5-minute execution.

{% code title="$ crontab -e" %}

```
*/5 * * * * bash /home/pi/crons/now-dns/script.sh
```

{% endcode %}

You can check the logs of crontab by running

```
tail -n 10 -f /var/log/syslog | grep CRON
```


# Remote ssh

To remotely access your Raspberry Pi using SSH, we only need to add a rule to your router so that it can route the incoming ssh traffic to your Raspberry. In particular, it will route incoming traffic at port 22 (default SSH port) to the SSH port of your Raspberry Pi.&#x20;

Before proceeding, make sure you have [configured your Raspberry](/home-setup/raspberry/untitled) accordingly and [enabled Dynamic DNS](/home-setup/remote-access/dynamic-dns).

Go to your router portal (e.g. 192.168.1.1) and enter your router admin credentials (they might be in the back of your router; otherwise reach out to your manufacturer / ISP). Got to the NAT section and add the rule.

![](https://cdn-images-1.medium.com/max/1600/1*6K1eeo3TbtyQrK4CDw8-sQ.png)

Time to test your connection!

```
$ ssh pi@lucas-example.2mydns.net
```


# Home VPN

Well, what about you wanting to access home network services from abroad? We can set this up by configuring a home VPN, so that whenever abroad, you can pretend to be within the home network!

**Setup PiVPN**

It all starts by installing PiVPN

```bash
curl -L https://install.pivpn.io | bash
```

**Follow this** [**tutorial**](https://www.wundertech.net/setup-wireguard-on-a-raspberry-pi-vpn-setup-tutorial/) **to set up PiVPN**. Make sure to choose “Wireguard” when in *Installation mode*. Select CloudFlare as your DNS provider (recommended). When in *Public IP or DNS* choose “DNS Entry” and write down your hostname (e.g. “lucas-example.2mydns.net”).

We recommend choosing a port other than the default one. Remember it though!

**Enable remote access**

Similarly, to what has been done with ssh service, now we have to configure the router accordingly so we VPN service can be accessed from the outside. In particular, we want to:

```
0.0.0.0:<VPN_NEW_PORT> -----> 192.168.1.X:<VPN_NEW_PORT>
```

**Note:** Use UDP protocol.

**Create and share profile**

Simply create a profile using

```
$ pivpn -a
```

and typing the name of the profile. The configuration files will be stored under /home/pi/configs. They are also stored (only accessible with root permissions) at /etc/wireguard/configs.

Prepare the devices you’d like to have access to the VPN by **installing Wireguard app** (available for Win/Mac/Linux/iOS/Android). Check App Store / Play Store or the equivalent.

To configure the connection with the phone, simply use the QR functionality

```
$ pivpn -qr <name-of-client>
```

If for a computer, we recommend accessing the file via ssh, and copying its content into Wireguard app.

To check available (created) client profiles type&#x20;

```
$ pivpn -l
```

and active clients (currently connected to the VPN) use

```
$ pivpn -c
```

**Note:** Once the profiles have been imported to the devices that will access remotely to the network, you can remove the files from /home/pi/configs/\*.conf

**Some issues**

It might not work, just try activating wireguard

* Activate wireguard using `wg-quick up /etc/wireguard/wg0.conf`, as proposed [here](https://askubuntu.com/questions/1216526/cannot-setup-wireguard-vpn).
* Activate ipv4 forwarding: `sudo systctl -w net.ipv4.ip_forward=1`, as proposed [here](https://pimylifeup.com/raspberry-pi-wireguard/). This command can be added to /etc/rc.local, so it is run everytime the system boots.
* You may have to add static route in your router. This is explained in the aforementioned tutorial and sort of connects vpn subnet and home subnet, use 10.6.0.0/24 as destination IP and 192.168.1.101 (raspi ip) as Gateway.

Other links:

* <https://github.com/pivpn/pivpn/issues/920>
* <https://pimylifeup.com/raspberry-pi-wireguard/> (wireguard)
* &#x20;<https://www.pcmag.com/how-to/how-to-create-a-vpn-server-with-raspberry-pi> (openvpn)

If additional problems, run PiVPN in debugging mode

```
$ pivpn -d
```


# GNU/Linux commands


# locale

Show available locales

```
locale -a
```

To update available locales, edit file in /etc/locale.gen uncommenting those locales to be added. Then run

```
sudo locale-gen
```

ref: <https://www.behova.net/configure-locale-on-arch-linux/>


# crontab

{% embed url="<https://crontab.guru/>" %}

{% hint style="info" %}

* [**Scheduling tasks with Cron**\
  *Cron is a tool for configuring scheduled tasks on Unix systems. It is used to schedule commands or scripts to run…*&#x77;ww.raspberrypi.org](https://www.raspberrypi.org/documentation/linux/usage/cron.md)
* [**Crontab.guru - The cron schedule expression editor**\
  *We created Cronitor because cron itself can't alert you if your jobs fail or never start. Cronitor is easy to integrate…*&#x63;rontab.guru](https://crontab.guru/)
  {% endhint %}


# chmod

Give permissions to users

{% hint style="info" %}
[chmod command online generator](https://chmodcommand.com/chmod-600/)
{% endhint %}


# router

## Check gateway

```
router -n
```


# Topics

* Python
* CI/CD (Travis CI, Codecov)
* Read The Docs
* pyenv
* pytest
* decoratos
* Jupyter notebooks
* Google Cloud services
* BQ query
* docker
* plotly
* pandas
* flake8
* rust


# Introduction to Sustainability


