# entries

title: GPU_versus_CPU
last_modified: 2024-10-18 18:55:56
body:
# GPU versus CPU

- GPU stands for _Graphics Processing Unit_. Originally designed for rendering
  graphics and video but now used for other applications of parallel computing
  eg. machine learning.

- The standard CPU uses sequential processing whereas the GPU is designed for
  parallel processing, specialising in performing many simple calculations
  simultaneously.

- Harnessing the GPU requires specialised programming approaches.

- Most standard laptops and desktops (if they are not designed for
  graphically-intensive tasks) incorporate graphics processing within the CPU.
  The CPU chip is on the same chip as the CPU chip. This is called _integrated_
  graphics processing.

- Some laptops, especially those marketed for gaming or professional work, have
  a separate GPU chip. This is a more powerful graphics processor, separate from
  the CPU.


title: Increasing_fractions_to_their_highest_terms
last_modified: 2024-10-18 19:15:04
body:
# Increasing fractions to their highest terms

Given the equivalence between factors and divisors we can increase fractions to
higher terms in a very similar way to when we reduce fractions. In the latter
case we are dividing by divisors to reduce. In the former, we are multiplying by
factors to increase.

> Whenever we increase a fraction, the resultant fraction will always be
> [equivalent](Equivalent%20fractions.md) to the fraction we started with.

## Demonstration

_Express $\frac{3}{4}$ as an equivalent fraction having the denominator 20_

$$
\\frac{3 \cdot 4}{5 \cdot 4} = \frac{12}{20}
$$

_Express $\frac{2}{3}$ as an equivalent fraction having the denominator 21_

$$
\\frac{2 \cdot 7}{3 \cdot 7} = \frac{14}{21}
$$

## Increasing fractions with variables to higher terms

_Express $\frac{2}{9}$ as an equivalent fraction having the denominator 18a_

In these cases, just append the variable to the factor:

$$
\\frac{2 \cdot 2a}{9 \cdot 2a} = \frac{4a}{18a}
$$


title: Python_application_structure
last_modified: 2024-10-18 18:55:56
body:
# Python application structure

## Directory layout

```
src/
    cli.py OR app.py
    constants.py
    __init__.py
tests/
requirements.txt
setup.py
```

## `requirements.txt`

Dependencies used within the venv for the project, e.g:

```
google-auth==1.35.0
google-auth-httplib2==0.1.0
google-auth-oauthlib==0.4.6
google-api-python-client==2.26.1
gspread==3.7.0
requests==2.25.1
oauth2client==4.1.3
```

## `setup.py`

The declaration file for the application, equivalent to `package.json`, e.g:

```py
from setuptools import setup, find_packages

setup(
    name="eolas-db",
    version="0.1",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    install_requires=[
        # List your project dependencies here
    ],
    entry_points={
        "console_scripts": [
            "eolas-db=cli:main",
        ],
    },
)
```

The `entry_points` key is important. This is the first execution point of the
application. Typically you would name your entry-point script as `app.py` or
`cli.py` and then specify its `main` function.

E.g. in `cli.py`:

```py
def main():
    print('run the application')

if __name__ == "__main__":
    main()

```

## `__init__.py`

See
[[Python_modules_and_imports#distinguishing-_modules_-from-_packages_]]|Python
modules]]


title: Daemons
last_modified: 2024-10-18 18:55:56
body:
# Daemons

A programme that runs in the background, performing a system function. A daemon
typically starts at boot or login without having to be specifically launched and
keeps running permanently or until manually stopped.

The custom is for the process name of daemons to end in the letter `d`.

> In the original Greek _daemon_ is translated as 'helper', it doesn't have the
> medieval connotation of a dark spirit but was used to denote the actions of a
> god rather than the god itself. A person could have a personal _daemon_ which
> determines their fate.


title: Multiplicative_identity
last_modified: 2024-10-18 18:55:56
body:
# The Property of Multiplicative Identity

**Let $a$ represent any member of $\mathbb{W}$ or $\mathbb{Z}$ then:**

$$ a \cdot 1 = a $$


title: Commutative_Property_of_Addition_and_Multiplication
last_modified: 2024-11-04 14:25:25
body:
# Commutative Property of Addition and Multiplication

**Let $a$, $b$ represent members of $\mathbb{W}$ or $\mathbb{Z}$ then:**

$$ a + b = b + a $$

$$ a \cdot b = b \cdot a $$


title: Difference_between_remote_origin_and_head
last_modified: 2024-10-18 18:55:56
body:
# Difference between _remote_, _origin_, _HEAD_

<dl>
<dt> remote
</dt>
<dd>
A remote is a git repository that is hosted on a server which you can interact with over a network. You can have more than one remote for a local repository.
</dd>

<dt>
origin
</dt>
<dd>
The default name given to the remote repository that was cloned. When you clone a repository, git automatically creates a default remote called `origin`. This is essentially an alias for the URL of this repository.
</dd>

<dt>HEAD</dt>
<dd>A reference to the most recent commit on the currently checked-out branch. It points to the tip of the branch which is the commit that was most recently added. If you have changes in your working directory that have yet to be committed, the HEAD will be behind them. Once you commit them, the HEAD will update to reflect the new commit.</dd>
</dl>


title: Quote_marks_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Quote marks in Bash

## Single-quotes (aka _strong_ quotes)

Bash will interpret everything in the string as a literal:

```bash
echo 'The directory is $(pwd)'
# The directory is $(pwd)
```

## Double-quotes

Bash will interpret strings as strings but will interpret expansions and
substitutions as executable processes:

```bash
$pointlessVar='directory'

echo "The ${pointlessVar}"

# The directory is /home/thomas
```

It is therefore generally best to use double quotes whenever we wish to return
mixed values.


title: Register_and_cache_memory
last_modified: 2024-10-18 18:55:56
body:
# Register and cache memory

The CPU has its own memory devices in the form of registers and cache memory.

[Registers](./CPU_architecture.md#Registers) are a form of memory that are
positioned on the same chip as the CPU. They are very fast but can only store a
small amount of data. They are used to store the results of calculations and the
addresses of the next instructions to be processed.

The cache is SRAM memory that is separate from the DRAM memory which comprises
the main memory. It exists in order to boost perfomance when executing the
read/request cycles of the steps detailed above.

There are two types of cache memory:

- L1 cache
  - Situated on the CPU chip itself
  - Fastest to access but stores less
- L2 cache
  - Situated outside of the CPU on its own chip
  - Slower to access than L1 but can store more data

The L1 cache is the fastest since the data has less distance to travel when
moving to and from the CPU. This said, the L2 cache is still very fast when
compared to the main memory, both because it is SRAM rather than DRAM and
because it is closer to the processor than the main memory.

Cache controllers use complex algorithms to determine what should go into the
cache to facilitate the best performance, but generally they work on the
principle that what has been previously used by the CPU will be requested again
soon. If the CPU has just asked for an instruction at memory location 555 it's
very likely that it will next ask for the one at 556, and after that the one at
557 and so on. The cache's controller circuits therefore go ahead and fetch
these from slow [DRAM to fast SRAM](./DRAM_and_SRAM_memory.md).


title: Analogue_and_digital
last_modified: 2024-10-18 18:55:56
body:
# Analogue and digital

Analogue and digital are paradigms for recording information, specifically
information about an object or state that obtains in the world.

![](/img/analog-digital.svg)

## Analogue

Here are two examples of analogue measurement/ capture:

- Measuring the temperature of a room with a mercury barometer
  - The mercury in the barometer expands or contracts in response to the heat of
    the ambient environment.
  - We say that the position of the mercury relative to the container represents
    the current temperature
- Measuring the weight of an object by placing it on a weighing scale
  - We say the position of the needle on the scale represents the weight of the
    object

> In each case, the position of the needle or the mercury isn't actually the
> temperature or the weight, it is a representation of this property. Thus in
> both cases, the analogue device works by analogy hence why we call it
> analogue.

This isn't the only sense in which "analogue" is used however. It doesn't always
mean an analagous representation of a physical property. We talk about
**analogue signals** as signals that vary continuously and which do not align to
digital values.

## Digital

### Limitations of analogue for computation

From a computing point of view, the data that can be captured and recorded by
analogue devices is simply too diverse and non-uniform. Computers are universal
machines whereas analogue devices typically only measure one property well.
Whereas a computer can record and playback music and take the temperature, to do
this in an analogue way would require a complex machine that can represent two
unrelated data sources. Imagine if a computer was able to achieve universality
through analogue means, it would most likely be very large physically and very
complex computationally since the computer would need to be able process data
from, e.g. for grooves on vinyl, needles on weighing sensors and mercury in
vacuum tubes.

> The types of analogue systems used are so different and variable that creating
> a common computing device that can understand all of them is nearly
> impossible.

Furthermore:

> Computers require highly reliable and accurate representations of certain
> types of data. Analogue representations of data can be difficult to measure
> precisely (and are potentially infinite), tend to decay over time, and lose
> fidelity when copied.

**Computers need a way to represent all types of data in a format that can be
accurately processed, stored and copied.**

### Why digital is better suited to computational requirements

A digital system represents data as a sequence of symbols where each symbol is
one of a limited set of values.

Computers only use two symbols for each value: 0 and 1.

Although a digital system could use more than two symbols, adding more would
[increase the complexity](Why_computers_use_binary.md#from-circuits-to-programs)
and cost of the system. A set of only two symbols allows for simplified hardware
and improved reliability.

All data within a computer from images to sounds are sequences of 0s and 1s. In
practice, the sequences are stored in various ways. On a CD, the binary digits
are stored as bumps (0) or flat spaces (1). On a flash drive, the 1s and 0s are
electrical charges etc.


title: Update_an_SQL_table
last_modified: 2024-10-18 18:55:56
body:
# Updating an SQL table

We use the `ALTER` query to add, remove and otherwise change the structural
properties of a table in the database.

## Add an additional field to existing table

This adds a `price` field to the `sales` table. The `price` field accepts data
of the type `real`.

```sql
ALTER TABLE sales ADD price real;
```


title: Factors_and_divisors
last_modified: 2024-10-18 19:13:52
body:
# Factors and divisors

The terms **factor** and **divisor** are used interchangeably. They are
different ways of expressing the same mathematical truth and this is because of
the inverse relationship between division and multiplication.

### Divisors

> For a number $n$, its divisor is any number that divides $n$ evenly without
> remainder: $$ \frac{a}{b} = 0 $$

In this operation, $a$ is the **divisor**, $b$ is the **dividend** and $0$ is
the **quotient**.

### Factors

> For a given number $n$, its factors are any pair of numbers that when
> multiplied together return $n$ as the product: $$ a \cdot b = n $$

We can see the relationship consists in the fact that factors are associated
with multiplication and divisors are associated with division: two different
perspectives on the same number relationships.

For example, 6 is both a factor and divisor of 18 and 24. To be precise, it is
the greatest common divisor of these two numbers.

As a divisor:

$$
\\frac{18/6}{24/6} = \frac{3}{4}
$$

As a factor:

$$
\\frac{3 \cdot 6}{4 \cdot 6} = \frac{18}{24}
$$

When we divide by the common divisor is acts as a divisor. When we multiply by
the common divisor it acts as a factor. The fact that the fractions are
[equivalent](Equivalent%20fractions.md) in both cases indicates that the
properties are equivalent.

## Greatest common divisor

> For two two integers $a, b$, $D$ is a common divisor of $a$ and $b$ if it is a
> divisor of both. The greatest common divisor is the largest value that $D$ can
> be whilst remaining a divisor to both $a$ and $b$.

### Demonstration

_Find the greatest common divisor of $18$ and $24$_

The divisors of 18: $$1, 2, 3, 6, 9, 18$$

The divisors of 24: $$ 1, 2, 3, 4, 6, 8, 12, 24$$

Thus the common divisors are: $$ 1, 2, 3, 6 $$

The largest value in the above set is 6, thus 6 is the greatest common divisor.

## Heuristics for finding divisors

1. For dividend $n$ , if $n$ ends in an even number or zero, $n$ is **divisible
   by 2**.
   1. $\frac{12}{2} = 6$
   1. $\frac{84}{2} = 42$
1. For dividend $n$ if the sum of the digits is divisible by 3 then $n$ is
   **divisible by 3**.
   1. $\frac{72}{3} = 24$
   1. $\frac{21}{3} = 7$
1. For a dividend $n$ if the number represented of the last two digits of $n$
   divides by 4 then $n$ is divisible by 4
   1. $\frac{324}{4} = 81$
   1. $\frac{532}{4} = 133$
1. For a dividend $n$, if the last digit of $n$ is divisible by 0 or 5, then $n$
   is divisible by 5.
   1. $\frac{25}{5} = 5$
1. For a dividend $n$, if $n$ is divisible by 2 and 3, then $n$ is divisible
   by 6.
   1. $\frac{12}{6} = 2$
   1. $\frac{18}{6} = 3$
1. For a dividend $n$, if the last three digits of $n$ are divisible by 8, then
   $n$ is divisible by 8.
   1. $\frac{73024}{8} = 9128$
1. For a dividend $n$, if the sum of the digits of $n$ is divisible by 9 then
   $n$ is divisible by 9.
   1. $\frac{117}{9} = 13$


title: SQLite
last_modified: 2024-12-27 15:08:29
body:
# SQLite

## Enabling foreign key constraints

Foreign key constraints are not enabled by default - it is very permissive. You
must manually turn them on, as part of the connection process:

```py
connection = sqlite3.connect("my_database.db")
connection.execute("PRAGMA foreign_keys = ON")
```

## INSERT OR IGNORE INTO

If table has a `UNIQUE` constraint on a field, insert if it is unique otherwise
skip without throwing a constraint error.

```sql
INSERT OR IGNORE INTO table_name (value) VALUES (:value)
```

## exec and fetchall

For `CREATE`, `INSERT`, `UPDATE`, `DELETE` operations it is sufficient to simply
use `execute` to carry out the operations:

```py
cursor = connection.cursor()
cursor.execute(sql)
```

For `SELECT` operations, you must add a return statement that uses `fetchall`:

```py
sql = "SELECT * FROM table"
cursor = connection.cursor()
cursor.execute(sql)
return cursor.fetchall()
```

## SELECT response data type

A `SELECT` operation returns a [list](Lists_in_Python.md) of
[tuples](Tuples_in_Python.md) where each entry in the tuple is a returned field.

For example:

```py
entries_sql = "SELECT title, size FROM entries"

entries_response = cursor.execute(entries_sql)
print(cursor.fetchall())
# [('Lorem ipsum', 127), ('Dolar sit', 4231)]
```


title: Morgan
last_modified: 2024-10-18 18:55:56
body:
# Morgan

Morgan is middleware that is used to log HTTP requests to the Express instance.

```js
app.use(morgan("dev"));
```

With Morgan in place, every time we run a request it will be logged on the
console that is running our Node application, e.g:

```plain
GET /api/courses 200 95 - 1.774 ms
```

This uses the `tiny` default which logs the bare minimum giving us: request
type; endpoint; response code; and time to execute. But there are more verbose
settings.

It defaults to logging on the console but can also be configured to write to a
log file.


title: Negation_Introduction
last_modified: 2024-10-18 18:55:56
body:
# Negation Introduction

This is also known as _proof by contradiction_. You start with an assumption
declared in a sub-proof. If you can derive a contradiction from this assumption
(typically from the introduction of another proposition and its negation), then
you are permitted to derive the negation of the auxiliary assumption in the main
proof.

![](/img/negate-intro.png)


title: Iterating_through_complex_data_structures_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Iterating through complex data structures in Python

// TODO: sections :

- Looping, mapping, filtering lists
- Looping, mapping, filtering dictionaries
- As above with multi-dimensional lists
- As above with list of dictionaries

## Complex data structures

In JavaScript when we return data from an API we tend to use an array of objects
as the canonical form of a repeating iterable, e.g:

```js
const data = [
  {
    name: "Thomas",
    age: 35,
  },
  {
    name: "Joe",
    age: 75,
  },
];
```

In Python there are two common ways to handle similar data structures:

- A list of lists:
  ```py
  data = [
    ["Thomas", 35],
    ["Joe", 75]
  ]
  ```
- A list of dictionaries:
  ```py
  data = [
     {"name": "Thomas", "age": 35},
     {"name": "Joe", "age": 75},
  ]
  ```

## Multi-dimensional lists (list of lists)

### Sorting by common property

Assuming the sub-lists have an identical structure, you can
[sort](Sorting_lists_in_Python.md) them by
a common property by passing a
[lambda function](Lambdas_in_Python.md) to
the `key` value of `sorted()` and `.sort()`.

For example, to sort the following list of lists by the second `age` property:

```python
people = [["Alice", 30], ["Bob", 25], ["Clare", 35], ["Dave", 28]]
```

Using `sorted()`:

```py
sorted_people = sorted(people, key=lambda x: x[1])
print(sorted_people)
# Output: [['Bob', 25], ['Dave', 28], ['Alice', 30], ['Clare', 35]]
```

Using `.sort`:

```py
people.sort(key=lambda x: x[1])
print(people)
# Output: [['Bob', 25], ['Dave', 28], ['Alice', 30], ['Clare', 35]]
```

If you want to sort by name instead, you could change the lambda function to
`lambda x: x[0]`:

```python
# Using sorted()
sorted_people = sorted(people, key=lambda x: x[0])
print(sorted_people)
# Output: [['Alice', 30], ['Bob', 25], ['Clare', 35], ['Dave', 28]]

# Using .sort()
people.sort(key=lambda x: x[0])
print(people)
# Output: [['Alice', 30], ['Bob', 25], ['Clare', 35], ['Dave', 28]]
```

### Updating an inner value within a multidimensional list

In the following example we have a list of the following structure:

```py
data = [
    ["1688582410", "Article One"],
    ["1688647447", "Article Two"],
    ["1689023491", "Article Three"],
]
```

Below we use
[map](Map_and_filter_in_Python.md) and a
[lambda function](Lambdas_in_Python.md) to
convert the first element of each iner list from a Unix timestamp to a readable
string:

```py
 readable_date = list(map(lambda i: [convert_timestamp(i[0])] + i[1:], date))
```

We could also use
[list comprehension](List_comprehension_in_Python.md)
to achieve the same outcome:

```py
readable_date = [[convert_timestamp(i[0])] + i[1:] for i in data]
```

### Filter elements in a multidimensional list

Say we have the following data structure:

```py
name_age = [ ["Anthony", 16], ["Christopher", 22], ["James", 6] ]
```

We can return only the people who are older than 18 with the following `filter`
function and `lambda`:

```py
filtered_ages = list(filter(lambda person: person[1] > 18, name_age))
```

### Remove duplicate entries from multidimensional list

If we are just working with a normal list, a quick way to remove duplicates is
just:

```py
our_list = [9, 9, 3, 2]
unique = list(set(our_list))
```

This won't work with a list of lists because lists are not hashable.

There are different approaches. Let's say we have the following multidimensional
list:

```py
dummy_data = [
    ["1689023491", "Article Three", "Lorem ipsum...", "https://example.com"],
    ["1688582410", "Article One", "Lorem ipsum...", "https://example.com"],
    ["1688647447", "Article Two", "Lorem ipsum...", "https://example.com"],
    ["1689023491", "Article Three", "Lorem ipsum...", "https://example.com"],
]
```

Here is one method:

```py
unique = []
seen = set()
for element in dummy_data:
    element_to_check = element[0]
    if element_to_check not in seen:
        unique.append(element)
        seen.add(element_to_check)
print(unique)
```

We designate a unique property in the inner lists and then store a unique record
of each. If the seen set doesn't have the incoming element, we add it to the
unique array.

It's more efficient to use a dictionary because it allows us to do this in 0(1)
time rather than 0(n):

```py
unique_dict = {x[0]: x for x in dummy_data}
unique_data = list(unique_dict.values())
```

This approach leverages the fact that a dictionary cannot have duplicate keys:
if you try to insert an element with a key that already exists, the new value
will simply overwrite the old value for that key.

Accordingly, we create a dictionary which uses the unique key in each list as
the key of each dictionary entry via
[dictionary comprehension](List_comprehension_in_Python.md#dictionary-comprehension)
that loops through each value in the inner lists of the multidimensional array.
We then parse the values of the dictionary into a list.

## List of dictionaries


title: Lambdas_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Lambdas in Python

In Python, anonymous functions like arrow-functions in JavaScript (`() => {}`)
are immediately invoked and unnamed. They are called lambdas.

Whilst they are unnamed, just like JS, the value they return can be stored in a
variable. They do not require the `return` keyword.

They are most often used unnamed with the functional methods
[map, filter](Map_and_filter_in_Python.md)
and reduce.

Here is the two syntaxes side by side:

```js
// JavaScript

const double = (x) => x * x;
```

```py
# Python

double = lambda x: x * x
```

Here is a lambda with multiple parameters:

```py
func = lambda x, y, z: x + y + z
print(func(2, 3, 4))
# 9
```

> Lambdas obviously enshrine functional programming paradigms. Therefore they
> should be pure functions, not mutating values or issueing side effects. For
> example, it would be improper (though syntactically well-formed) to use a
> lambda to `print` something


title: Create_Mongo_database
last_modified: 2024-10-18 18:55:56
body:
# Creating a MongoDB database

First create a directory for the database and set permissions:

```bash
$ mkdir /data/db
$ sudo chown -R `id -un` /data/db
```

Then start the Mongo daemon

```bash
mongod
```

This will run continuously in the terminal and should say somewhere that it is
waiting for connections on port `27017`. This command must be executed before
you run any backend that interacts with the Mongo database.

## MongoDB Compass

_Compass_ is a graphical interface for viewing and interacting with the data in
your Mongo database. It will automatically load to the default Mongo port:
`27017`.

![](/img/mongo-compass.png)


title: Prop_types_in_React
last_modified: 2024-10-18 18:55:56
body:
# Prop types

**The `prop-types` package allows us to introduce type-checking during the
development runtime of a React application. With larger applications or those
with complex data flows, this can help reduce errors and bugs during
development. This is a bit like using TypeScript but on a more minimal level.**

## Install

```
npm install prop-types
```

## Usage

```jsx
import PropTypes from "prop-types";
```

## Examples

Say we have a component with the following props:

```jsx
function Page(props) {
  const classes = useStyles();
  return (
    <React.Fragment>
      <Typography className={classes.heading} variant="h1">
        {props.h1}
      </Typography>
      {props.h2 !== "" && <Typography variant="h2">{props.h2}</Typography>}
      {props.paras.map((paragraph, index) => (
        <Typography
          className={classes.paragraph}
          key={index}
          variant="body1"
          gutterBottom
        >
          {paragraph}
        </Typography>
      ))}
      {props.children}
      <Button
        className={classes.button}
        variant="contained"
        color="primary"
        disableElevation
        component={Link}
        to={props.buttonLink}
      >
        {props.buttonText}
      </Button>
    </React.Fragment>
  );
}
```

Before the final `export default` statement, we would add a PropTypes object
that specifies the data or reference type that is required by each prop cited in
the component:

```jsx
Page.propTypes = {
  h1: PropTypes.string.isRequired, // should be string data type, must be present
  h2: PropTypes.string, // as above but optional
  paras: PropTypes.array, // should be array reference type
  buttonLink: PropTypes.string,
  buttonText: PropTypes.string,
  children: PropTypes.node, // can be anything (element, type, JSX) that is rendered to the screen
};
```

If one of these type checks failed you get a very semantic Warning in the
console specifying which prop is not consistent with your prop type declaration.

## Additional checks

Above are the most frequent and basic checks, but there are many other
conditions you can check for:

```jsx
// The full list of types
[propName]: PropTypes.array,
[propName]: PropTypes.bool,
[propName]: PropTypes.func,
[propName]: PropTypes.number,
[propName]: PropTypes.object,
[propName]: PropTypes.string,
[propName]: PropTypes.symbol,

// Anything that can be rendered: numbers, strings, elements or an arrayor fragment) containing these types.
[propName]: PropTypes.node,

// A function

[propName]: PropTypes.func

// An object that could be one of many types
[objectProp]: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
  ]),

// An array of a certain type
[arrayProp]: PropTypes.arrayOf(PropTypes.number),

// An object with property values of a certain type
[objectProp]: PropTypes.objectOf(PropTypes.number),
```


title: User_management_in_Linux
last_modified: 2024-10-18 18:55:56
body:
# User management

## Switch user

If already logged in as a user you can switch users with the command
`su - [username]`.

## Login as root

If you are logged in as a standard user, if you use `su -` without specifying a
username, then it will assume you wish to log in as root.

If you wish to login as root in the tty at startup, then use `root` as the
username.


title: Redirect_to_dev_null
last_modified: 2024-10-18 18:55:56
body:
# Redirecting to `/dev/null`

You'll see the following a lot when reading shell scripts:

```bash
[some_command] > /dev/null 2>&1
```

This is a redirection statement. It is redirecting data to the `null` device on
Unix systems. Basically to a black hole or shredder where you can't access it
because you don't want it to be output to `stdout`.

The `2>&1` argument is the content: any errors that the program may generate and
try to show in stout. Notice we are using the
[file descriptors](File_descriptors_and_redirection.md)
`1` and `2`.

If you just want the errors regardless of whether they appear in `stdout` you
do:

```bash
[some_command] > /dev/null 2>
```

## Example

I have used this in my Mongo start-up script:

```
mongodb-compass > /dev/null 2>&1
```

Here, I just want the MongoDB Compass application to start, I don't care if it
wants to output complaints to the stout.


title: Matter_and_atoms
last_modified: 2024-10-18 18:55:56
body:
# Matter and atoms

## Matter, elements, compounds and mixtures

- Matter is anything that occupies space and has weight. It may be found in any
  one of three states: liquid, solid, or gas.
- Matter can be classed in terms of **elements**, **compounds** and
  **mixtures**.
  - An element is a substance that cannot be reduced to a simpler substance by
    chemical means.
  - The chemical combination of two or more elements is a compound. Compounds
    _can_ be separated or reduced by chemical means but they cannot be
    physically separated.
  - A _physical_ (note not _chemical_) combination of elements and compounds is
    a mixture.
  - For example "air" is a mixture which is made up of oxygen, nitrogen, carbon
    dioxide, and other gases.

## Atoms and molecules

- Elements are made up of **atoms**.
- A **molecule** is a type of compound where the atoms of two types of elements
  have joined together. For example sodium and chlorine are two elements that
  can join to form sodium chloride. We call this **chemical bonding**.

## Atomic particles
![](/img/atom-diagram.svg)



- There are three particles comprising atoms: **protons**, **neutrons** and
  **electrons**.

- Protons and neutrons comprise the nucleus of the atom. A proton is positively
  charged. A neutron has no charge.

- Electrons orbit around the nucleus in concentric rings. Electrons are
  negatively charged. Because of this protons and electrons attract each other.

### Atomic number

- The number of protons in the nucleus is called the element's **atomic**
  number.
- We use the atomic number of elements to distinguish one element from another.

### Atomic weight

- The atomic weight of an atom is its mass.
- The mass is determined by the number of protons and neutrons in the nucleus.
- An electron $\frac{1}{1845}$ the mass of a proton. Its mass is so neglible
  that it makes no significant difference to the atomic weight.


title: Working_with_directories_in_Python
last_modified: 2024-11-13 19:32:16
body:
# Working with directories in Python

## List files in a directory

```py
# Here we list the file exts of files in a dir
import os
from pathlib import Path

with os.scandir("/a/directory") as dir:
    for entry in dir:
        print(Path(entry).suffix)
```

## List files without extension

```python

file = "/some/file/with/markdown.md"
return os.path.splitext(os.path.basename(file))[0]
# markdown
```

## Create a directory

```py
import os

os.makedirs("/name/of/directory")
```

### Check if directory exists, remove if so

```py
import os
import shutil

if os.path.isdir("/name/of/directory")
    shutil.rmtree(target_dir)
```

## Copy a nested directory from location to another

```py
import shutil

shutil.copytree("/source/dir", "/target/dir", dir_exist_ok=True)
```


title: Docker_general_overview
last_modified: 2024-10-18 18:55:56
body:
# Docker: general overview

> Docker is an ecosystem of tools for creating, running and transporting
> containers.

The main product of the Docker company is Docker Desktop - a UI for running
containers however the actual `docker` software is free and open source.

Docker standardised the use of containers set up the open-source Open Container
Initiative which is a convention agreed upon by the major tech companies. It
codifies the following:

- Docker runtime specification
- Docker image specification
- Docker registry specification

## Main components

- **Docker Engine**
  - The core component
  - Exposes the Docker API and manages the entire workflow around creating,
    running and deploying containers
- **Docker Client**
  - The Docker CLI
  - The primary means of interacting with the Docker Engine
  - Provides commands for managing images, containers and other Docker objects
- **Docker Compose**
  - A tool for defining and running multi-container applications
  - Define the configuration for all of the containers that make up the
    application in a single YAML file
- **Docker Images**
  - See below
- **Docker Containers**
  - See below
- **Docker Registry**
  - A centralised location where Docker iamges can be stored and shared
  - DockerHub is the registry provided by Docker
  - Organisations can set up their own private registries

## Docker images

An image is a blueprint that contains the instructions to build a container.
It's an immutable snapshot of the file system and configuration of an
application. Images can be easily shared between developers.

They are runnable packages that contain everything needed to run an application
including the binaries, libraries, resources and other dependencies.

It does not contain an operating sytem but may include a particular Linux
distribution.

## Docker containers

A container is a runnign instance of a Docker image. Multiple, identical
containers can be launched from the same, single image.

## Docker architectural overview

See [Docker architecture](Docker_architecture.md).


title: Equivalent_equations
last_modified: 2024-10-18 19:13:14
body:
# Equivalent equations

> Two equations are equivalent if they have the same
> [solution](Algebra%20key%20terms.md#678811) set.

We know from the distributive property of multiplication that the equation
$a \cdot (b + c )$ is equivalent to $a \cdot b + a \cdot c$. If we assign values
to the variables such that $b$ is $5$ and $c$ is $2$ we can demonstrate the
equivalence that obtains in the case of the distributive property by showing
that both $a \cdot (b + c )$ and $a \cdot b + a \cdot c$ have the same solution:

$$ 2 \cdot (5 + 2) = 14 $$

$$ 2 \cdot 5 + 2 \cdot 2 =14 $$

When we substitute $a$ with $2$ (the solution) we arrive at a true statement
(the assertion that arrangement of values results in $14$). Since both
expressions have the same solution they are equivalent.

## Creating equivalent equations

We can create equivalent equations by adding, subtracting, multiplying and
dividing the _same quantity_ from both sides of the equation (i.e. either side
of the $=$ symbol). Adding or subtracting the same quantity from both sides
(either side of the $=$ ) of the equation results in an equivalent equation.

### Demonstration with addition

$$
x - 4 = 3
$$

The [solution](Algebra%20key%20terms.md#678811) to this equation is $7$

$$
x -
4 (+4) = 3 (+ 4)
$$

Here we have added $4$ to each side of the equation. If $x = 7$ then:

$$ 7 - 4 (+ 4) = 7 $$

and:

$$ 3 + 4 = 7 $$

### Demonstration with subtraction

$$
x + 4 = 9
$$

The [solution](Algebra%20key%20terms.md#678811) to this equation is $5$.

$$
x +
4 (-4) = 9(-4)
$$

Here we have subtracted $4$ from each side of the equation. If $x = 5$ then:

$$ 5 + 4 (-4) = 5 $$

and

$$ 9 - 4 = 5 $$

### Demonstration with multiplication

$$x \cdot 2 = 10  $$ The [solution](Algebra%20key%20terms.md#678811) to this
equation is $5$.

$$
(x \cdot 2) \cdot 3 = 10 \cdot 3 $$ Here we have multiplied each side of the
equation by $3$. If $x =5$ then

$$ (5 \cdot 2) \cdot 3 = 30$$
$$ 10 \cdot 3 = 30$$

### Demonstration with division

$$x \cdot 3 = 18  $$
The [solution](Algebra%20key%20terms.md#678811) to this equation is $6$.
$$\frac{x
\cdot 3}{3} = \frac{18}{3}
$$

Here we have divided each side of the equation by $3$. If $x$ is 6, then

$$
\frac{6
\cdot 3}{3} = 6
$$

$$\frac{18}{3} = 6 $$


title: Object_language_and_meta_language
last_modified: 2024-10-18 18:55:56
body:
# Object and metalanguages

When we talk about a language we call that language the **object language**. A
**metalanguage** is a language used to describe some object language.

When we are developing a formal logical language (which we may call SL or PL for
'sentential' and 'propositional' logic respectively), the formal language is the
object language and natural language (e.g. English) is the metalanguage.

**Demonstration**

If we talk about German in English, German in the object language and English is
the metalanguage.

## Use and mention

There is an associated distinction: that of use and mention.

When we create an expression in a language we are said to _use_ that language.
When we remark upon said expression we are said to be _mentioning_ the language.
This distinction may correspond to the object and metalanguage difference above
but doesn't have to; use and mention can happen in the same language. For
example:

```
'London' is the word that denotes the capital of the UK.
```

## Metavariables

A metalinguistic variable (metavariable for short) is an expression in the
metalanguage that is used to talk generally about expressions of the object
language. The convention in these notes will be to embolden single letters when
these letters are used as metavariables.

For example, instead of saying _'P & Q' is an expression comprising two atomic
sentences and a conjunction_ we might say **\*P** is an expression comprising
two atomic sentences and a conjunction. In this instance **P** is a metavariable
in the metalanguage mentioning the expression P & Q in the object language


title: Regular_expressions_in_SQL
last_modified: 2024-10-18 18:55:56
body:
# Regular expressions in SQL

```sql
SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

Guyana
Mexico
Myanmar
```


title: Logarithms
last_modified: 2024-10-18 18:55:56
body:
Most simply a logarithm is a way of answering the question:

> How many of one number do we need to get another number. How many of x do we
> need to get y

More formally:

> x raised to what power gives me y

Below is an example of a logarithm:

$$
\log \_{3} 9


$$

We read it:

> log base 3 of 9

And it means:

> 3 raised to what power gives me 9?

In this case the answer is easy: $3^2$ gives me nine, which is to say: three
multiplied by itself.

## Using exponents to calculate logarithms

This approach becomes rapidly difficult when working with larger numbers. It's
not as obvious what $\log \_{5} 625$ would be using this method. For this
reason, we use exponents which are intimately related to logarithms.

A logarithm can be expressed identically using exponents for example:

$$
\log \_{3} 9 = 2 \leftrightarrow 3^2 = 9


$$

By carrying out the conversion in stages, we can work out the answer to the
question a logarithm poses.

Let's work out $\log \_{2} 8$ using this method.

1. First we add a variable (x) to the expression on the right hand:

   $$
   \log \_{2} 8 \leftrightarrow x


   $$

1. Next we take the base of the logarithm and combine it with x as an exponent.
   Now our formula looks like this:

   $$
   \log \_{2} 8 \leftrightarrow 2^x


   $$

1. Next we add an equals and the number that is left from the logarithm (8):

$$
\log \_{2} 8 \leftrightarrow 2^x = 8


$$

Then the problem is reduced to: how many times do you need to multiply two by
itself to get 8? The answer is 3 : 2 x 2 x 2 or 2 p3. Hence we have the balanced
equation:

$$
\log \_{2} 8 \leftrightarrow 2^3 = 8


$$

## Common base values

Often times a base won't be specified in a log expression. For example:

$$
\log1000


$$

This is just a shorthand and it means that the base value is ten, i.e that the
logarithm is written in denary (base 10). So the above actually means:

$$
\log \_{10} 1000 = 3


$$

This is referred to as the **common logarithm**

Another frequent base is Euler's number (approx. 2.71828) known as the **natural
logarithm**

An example

$$
\log \_{e} 7.389 = 2


$$


title: Unknown_type_in_TS
last_modified: 2024-10-18 18:55:56
body:
# Unknown

You might think that a good use case for `any` is a scenario where you don't
know in advance what the data type is going to be.

In order to mark that this is the case, you type the value as `any`. In fact,
TypeScript provides a type for this specific scenario: `unknown`.

Like `any`, `unknown` is equivalent to every type in TS (it is also a supertype)
but it is deliberately inhibiting, in contrast to `any`. When you use `unknown`
you have to use type narrowing to avoid it being returned. So if your code
starts with `unknown`, you should filter out scenarios where it evaluates to
each of the possible types otherwise if `unknown` is returned it will cause an
error.


title: Logical_truth_and_falsity
last_modified: 2024-10-18 18:55:56
body:
# Logical truth and falsity

We say of certain propositions that they are logically true or logically false.

## Logical falsity

### Informal definition

A proposition is logically false if and only if **it is not possible for the
proposition to be true**. The proposition itself cannot be consistently
asserted.

**Demonstration**

```
There is a country that is not a country.
Apples are fruits and apples are not fruits
```

Neither proposition can be true because the truth of the first clause is
contradicted by the second. By the principle of
[consistency](Logical_consistency.md), it is not
possible for both clauses to be true at once therefore the proposition, overall
has the truth value of false.

```
It is raining and it is not raining.
```

### Formal definition

> A proposition P is truth-functionally false if and only if P is false on every
> truth-value assignment

### Formal expression

$$ P \land \lnot P $$

### Truth-table

| $P$ | $P \land \lnot P$ |
| --- | ----------------- |
| T   | F                 |
| T   | F                 |

## Logical truth

### Informal definition

A proposition is logically true if and only if it is not possible for the
proposition to be false. The proposition itself cannot be consistently denied.

**Demonstration**

```
A rose is a rose.
Today is Tuesday unless today is not Tuesday.
```

Regardless of any facts obtaining in the world, these propositions cannot be
false.should be avoided in arguments, they 'prove' everything whi

As with logically false propositions, logical truth can also apply to compound
propositions:

```
A rose is a rose and a shoe is a shoe
```

### Formal definition

> A proposition P is truth-functionally true if and only if P is true on every
> truth-value assignment

$$ P \lor \lnot P$$

### Truth-table

| $P$ | $P \lor \lnot P$ |
| --- | ---------------- |
| T   | T                |
| F   | T                |

### Consequences

The existence of logically false and logically true propositions affects the
validity and soundness of arguments in which they are used. These are
technicalities that have philosophically interesting consequences.

- If an argument contains premises which are logically false than this argument
  will perforce be valid. This is because one cannot consistently assert the
  premises and deny the conclusion which is the definition of
  [validity](Validity_and_entailment.md). However the
  _reason_ why one cannot consistently assert the premises and deny the
  conclusions is because one cannot consistently assert the premises - they
  conflict with each other. Furthermore as the argument contains false premises,
  it cannot be sound.

  ```
  (P1) Russia is a country.
  (P2) Russia is not a country
  (P3) All countries have languages.
  ____________________________________________
  (C) Russian is a language.
  ```

- Any argument with a logically true conclusion is valid. Because the conclusion
  cannot be consistently denied it follows that we cannot consistently assert
  the premises _and_ deny the conclusion. Whether or not the argument is sound
  remains an open question however. If the premises happen to be true then the
  argument will be sound on the strength of the conclusion being logically true
  but if the premises are false it will be unsound regardless of the truth of
  the conclusion.

  ```
  (P1) Horses have legs.
  (P2) Animals with legs can move.
  ____________________________________________
  (C) A horse is a horse
  ```


title: Remote_tracking_branches
last_modified: 2024-10-18 18:55:56
body:
# Remote tracking branches

A remote tracking branch is a **local** snapshot or reference to the state of a
branch on a remote repository.

When you clone a remote repository, Git automatically creates remote tracking
branches for all the branches on the remote repository.

The remote tracking branches have the prefix `origin/` followed by the name of
the remote branch. For example, if you clone a repository with a branch named
`develop`, Git creates a remote tracking branch named `origin/develop`.

When you use commands like `git fetch` and `git pull`, you are interacting with
the remote repository and having it reflected in the remote tracking branches.

For instance, `git fetch` makes the remote tracking branch reflect the remote
changes so that you have a local copy.

The remote tracking branch is not the same as a local branch. A local branch is
a branch that may or may not exist on the remote. Once it has been pushed to the
remote repository, a remote tracking branch will be created for its remote
version. When you make local changes, the snapshot of the remote tracking branch
will no longer be up to date: your local branch will be "ahead" of it. Once you
push, the remote tracking branch snapshot is update and reflects the local state
of the branch and the two are in sync again.

The same is true of remote branches. When you checkout a remote branch, your
local version of it reflects a remote tracking version of it. This goes out of
sync with your local version when changes are made on the remote.


title: Typing_built_in_React_hooks
last_modified: 2024-11-04 14:24:05
body:
# Typing built-in React hooks

## `useState`

```tsx
const [amount, setAmount] = useState<number | string>(3);
```

### With a ustom type

```tsx
interface IState {
  people: IPerson[];
}

interface IPerson {
  name: string;
  age: number;
}

const [people, setPeople] = useState<IState>({});

// Alternative declaration

interface IState {
  people: {
    name: string;
    age: number;
  }[];
}

const [people, setPeople] = useState<IState["people"]>({});
```

## `useReducer`

Mostly the same. They key thing to type is the reducer function itself. You
don't need to type the intitial state unless it is a pre-existing type, you can
just use type assertion:

```jsx
interface IAction {
  | { type: "increment"; payload: number }
  | { type: "decrement"; payload: string };
}

const initialState = { count: 0 };

function reducer(state: typeof initialState, action: IAction) {
  switch (action.type) {
    case "increment":
      return { count: state.count + action.payload };
    case "decrement":
      return { count: state.count - Number(action.payload) };
    default:
      throw new Error();
  }
}
```

Then the syntax is as normal, i.e:

```js
const [state, dispatch] = useReducer(reducer, initialState);
```

## `useEffect`

> Limited potential for typing here as this hook does not return a value. See if
> there is useful inferred typing from use and update.

## `useContext`

We can use generics but mostly this is untyped:

```jsx
type Theme = "light" | "dark";
const ThemeContext = createContext < Theme > "dark";

const App = () => (
  <ThemeContext.Provider value="dark">
    <MyComponent />
  </ThemeContext.Provider>
);

const MyComponent = () => {
  const theme = useContext(ThemeContext);
  return <div>The theme is {theme}</div>;
};
```

## `useCallback` / `useMemo`

You must only type the parameters that are passed to the callback, the return
value will be inferred.


title: Coulombs_Laws
last_modified: 2024-10-18 18:55:56
body:
# Coulombs Laws

Coulomb's Laws express the fundamental relationship between electric charge,
force and attraction. They are also known as the **Electrostatic Laws** and
define **the electic force**.

## First Law

> Like charges of electricity repel each other. Unlike charges attract each
> other.

Within the atom we see this at work in the way that negatively charged electrons
are attracted to the positively charged nucleus. This attractive force is
balanced by the centrifugal force caused by the electron's rotation around the
nucleus. This keeps the electrons in orbit. Without it, they would spiral into
the nucleus.

Within circuits, the first law dictates the movement of charge from negatively
charged atoms to positively charged atoms through the conductor.

## Second Law

The attraction or repulsion between charges acts along the line between the two
charges.

## Third Law

The size of the electric force varies inversely as the square of the distance
between the two charges. Thus if the distance between the two charges is
doubled, the attraction or repulsion becomes weaker, decreasing to a quarter of
the original value.

## Fourth Law

The size of the electric force is proportional to the value of each charge
measured in coulombs.


title: Modules_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Modules

> Modules are partitioned files where we define our variables and functions.
> Values defined in modules are scoped to that specific module, constituting a
> unique name space. This avoids name clashes in large programs.

- Every file in a Node application is considered a module.

- The variables and methods in a module are equivalent to `private` properties
  and methods in object-oriented programming.

- If you wish to use a function or variable defined in a module outside of its
  modular container you need to explicitly export it and make it public.

## Structure of a module

Node keeps an internal record of the properties of a module. To see this we can
log the property `module` to the console.

```js
// index.js
console.log(module);
```

This gives us:

```plaintext
Module {
 id: '.',
 path: '/home/thomas/repos/node-learning',
 exports: {},
 filename: '/home/thomas/repos/node-learning/index.js',
 loaded: false,
 children: [],
 paths: [
   '/home/thomas/repos/node-learning/node_modules',
   '/home/thomas/repos/node_modules',
   '/home/thomas/node_modules',
   '/home/node_modules',
   '/node_modules'
 ]
}
```

## Exports

- Whenever we export a property or method from a module we are directly
  targeting the `exports` property of the module object.
- Once we add exports to a file they will be displayed under that property of
  the module object.
- We can export the entire module itself as the export (typically used when the
  module is a single function or class) or individual properties.

### Exporting a whole module

_The example below is a module file that consists in a single function_

```js
module.exports = function (...params) {
  // function body
};
```

Note the module is unnamed. We would name it when we import:

```js
const myFunction = require("./filenme");
```

### Exporting sub-components from a module

In the example below we export a variable and function from the same module.
Note only those values prefixed with `exports` are exported.

```js
exports.myFunc = (...params) => {
  // function bod[]()y
};

exports.aVar = 321.3;

var nonExportedVar = true;
```

This time the exports are already name so we would import with the following:

```js
const { myFunc, aVar } = require("./filename");
```

We can also do the exporting at the bottom when the individual components are
named:

```js
const myNamedFunc = (val) => {
  return val + 1;
};

function anotherNamedFunc(val) {
  return val * 2;
}

// This time we export at the bottom
exports.myNamedFunc = myNamedFunc;
exports.differentName = anotherNamedFunc; // We can use different names

// Or we could export them together
module.exports = { myNamedFunc, anotherNamedFunc };
```

The import is the same:

```js
const { myNamedFunc, anotherNamedFunc } = require("./modules/multiExports");
```

## Structuring modules

The techniques above are useful to know but generally you would want to enforce
a stricter structure than a mix of exported and private values in the one file.
The best way to do this is with a single default export.

Here the thing exported could be a composite function or an object that
basically acts like a class with methods and properties.

_Export a composite single function_

```js

module.exports = () => {
	foo() {...}
	bar() {...}
}
```

_Export an object_

```js

module.exports = {
	foo : () => {...},
    bar: () => {...}
}
```

**Both of these structures would be referred to in the same way when importing
and using them.**

Or you could export an actual class as the default. This is practically the same
as the two above other than that you would have to use `new` to initiate an
instance of the class.

```js
export default class {
  foo() {}
  bar() {}
}
```

Every method and property within the export will be public by default, whether
it is an object, class or function. If you wanted to keep certain
methods/properties private, the best approach is to define them as variables and
functions within the module file but outside of the `export` block.


title: Writing_to_files_in_Python
last_modified: 2024-10-25 09:34:09
body:
# Writing to files in Python

We create a file object with `open()` and use the `write` method:

```py
# Open file in write mode
file = open("example.txt", "w")

# Write some text to the file
file.write("Hello, this is an example text written using Python.")

# Close the file
file.close()
```

Alternatively we use `with open` which automatically closes the file:

```py

with open("example.txt", "w") as file
    file.write('some lines')

```

> Note that in the above example, if the file does not already exist, it will
> create it. If it does exist, it will overwrite its contents with the new data.
> So we use `write` to create new files as well as to write to existing files.


title: Streams_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Handling streams with fs

When reading from a file, the
[`fs.readFile()`](fs.md) method waits
until the entire file has been read before executing the callback. It's obvious
why this might not be ideal in certain cases. If the file is very large you are
utilising a lot of [memory](Memory.md) for a
single process. Additionally, the data you need might appear early in the file,
in which case, once you find the data you want, there is no need to read to the
end of the file.

> An example of this in practice is watching a Netflix film: we don't have to
> wait for the whole film to download, we can start watching it immediately
> because it is passed to us in chunks.

## Reading streams

This is why the ability to read files and data as streams exists in Node.js.
Streams promote memory and time efficiency. As you are not necessarily reading
the whole file, you can extract the data you need quickly and you are not
putting the whole file in memory.

When read as a stream, the file is broken up into smaller chunks. Readable
streams raise data events and pass the chunks to our callbacks. Hence we don't
have to wait for the whole file before registering data chunks.

## Implementation

Instead of, e.g :

```js
fs.readFile("./lorem.md", "UTF-8", function (err, fileContents) {
  console.log(fileContents);
});
```

We would:

```js
let stream = fs.createReadStream("./lorem.md", "UTF-8");

let data;

stream.once("data", (chunk) => {
  console.log("read stream started");
});

stream.on("data", (chunk) => {
  data += chunk;
  console.log(data);
});

stream.on("end", () => console.log("stream ends"));
```

We use `once` to do something at the moment the stream starts to be read.

We use `on` to target the `"data"` and `"end"` events. We use this to log the
chunks via the `data` variable.

## Writing streams

When we write as a stream, we break data up and pass this to a reader as a
stream. It is what creates a stream in the first place.

For example we could create a stream that handles `stdin` and writes this to a
file in chunks:

```js
var stream = fs.createWriteStream("lorem.txt")

process.stdin.once("data", (data) => {
    stream.write(data, function() => {
        // data is now written.
    })
})

process.on("exit", function () {
    stream.close()
})
```

Note that we always have to close the stream on exit


title: Numbers_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Numbers in Python

## Distinguishing `int` and `float`

- In Python we have floats and integers and we can coerce one into the other
- A `//` as an operator means float division. This obviously provides greater
  precision than int division `/`.
- There is no increment (`++`) or decrement (`--`) operator in Python

```python
# Integers and floats
count = 1
print(count)
# 1
print(type(count))
# <class 'int'>

exchange_rate = 1.83
print(exchange_rate)
# 1.83
print(type(exchange_rate))
# <class 'float'>

print(float(count))
# 1.0

print(int(exchange_rate))
# 1
```


title: Creating_a_RESTful_API_PUT
last_modified: 2024-10-18 18:55:56
body:
# Creating a RESTful API: `PUT` requests

To demonstrate the handling of PUT requests, we will create a handler that
updates an element in the course array, based on its `id` and return the updated
entry:

```js
router.put("/:id", (req, res) => {
  const course = courses.find((c) => c.id === parseInt(req.params.id));

  if (!course)
    return res.status(404).send("A course with the given ID was not found");

  const { error } = validateCourse(req.body);

  if (error)
    return error.details.map((joiErr) => res.status(400).send(joiErr.message));

  course.name = req.body.name;
  res.send(course);
});
```

Our request:

```js
const updateCourse = async (courseChange) => {
  try {
    const resp = await axios.put("http://localhost:3000/api/courses/1", {
      name: courseChange.name,
    });
    console.log(resp.data);
  } catch (err) {
    console.error(err);
  }
};

updateCourse({ name: "A new course" });
```

Returns:

```js
{ id: 1, name: 'A new course' }
```


title: Command_pattern
last_modified: 2024-10-18 18:55:56
body:
# Command pattern

This is typically used when you want to sequence a fairly large number of
actions in a series with the option to undo or reverse them. Similarly to the
mediator it has a one-to-many architecture (there is a central class that
sequences the commands which are handled by other classes) but in addition to
sending and routing requests between colleagues, it keeps a central store of
them and can reverse actions.

The typical example is a calculator. Will will generate this using constructor
function syntax, rather than ES6 class syntax.

You have a bunch of arithmetic functions:

```jsx
function add(x, y) {
  return x + y;
}
function sub(x, y) {
  return x - y;
}
function mul(x, y) {
  return x * y;
}
function div(x, y) {
  return x / y;
}
```

Then a generalised `Command` class that has three parameters: undo, execute, and
return a value:

```jsx
var Command = function (execute, undo, value) {
  this.execute = execute;
  this.undo = undo;
  this.value = value;
};
```

We then create the specific commands by combining the functions and the
`Command` class:

```jsx
var AddCommand = function (value) {
  return new Command(add, sub, value);
};

// We would create one of these classes for each of the four operations
```

So now the `add` and `subtract` functions slot into `execute` and `undo` on the
`Command` class.

Finally we create the centralised command class that will return values based on
the individual commands it sequences and issues, store them and remove them:

```jsx
var Calculator = function () {
    var current = 0;
    var commands = [];

    function action(command) {
        var name = command.execute.toString().substr(9, 3);
        return name.charAt(0).toUpperCase() + name.slice(1);
    }

    return {
        execute: function (command) {
            current = command.execute(current, command.value);
            commands.push(command);
            log.add(action(command) + ": " + command.value);
        },

        undo: function () {
            var command = commands.pop();
            current = command.undo(current, command.value);
            log.add("Undo " + action(command) + ": " + command.value);
        },

        getCurrentValue: function () {
            return current;
        }
    }
```

```jsx
calculator.execute(new AddCommand(100));
calculator.execute(new SubCommand(24));
calculator.execute(new MulCommand(6));
calculator.execute(new DivCommand(2));
```

Or undo them with:

```jsx
calculator.undo();
```


title: Components_props_classes
last_modified: 2024-10-18 18:55:56
body:
# Components and props with class-based components

A **component** is a class or a function that manages the content that is output
on the page (the rendering of **elements**) and the data (**props**) and state
that is applied to the elements that are output.

**Components can be created using ES6 classes or using the newer hook
methodology.**

A class-based component is a mixture of standard Javascript, JSX Javascript and
HTML wrapped within an extension of the `React.Component` **class** that you
import into your custom JS when installing the React library:

```js
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
```

The JSX content of the component lives within the `render()` method that belongs
to the `React.Component` class.

Once we have defined a class component that contains a JSX element we can then
use JSX tags to place the resulting React element in our page. This is a
placeholder for the HTML that is rendered by the class component. For example:

```html
<body>
  <Welcome name="Thomas" />
</body>
```

> A class component must include `render()`, and the return can only return one
> parent element. Also there _must be_ a parent component. Where this isn't
> possible, the convention is to use empty opening and closing tags, viz:
> `<>...</>` . These are called **React Fragments** and this is actually a short
> hand for `<React.Fragment>...</React.Fragment>`

## Class components with state

Most class components will also possess state. State is managed through the
constructor method on the class component, for example:

```jsx
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
```

We use the `super()` method to inherit the parent constructor (because custom
components extend the React Component parent class) and we pass state as a
special kind of prop.

## Class components and simple components

Within the class-based paradigm of React a distinction is made between simple
and class components.

A class component is obviously a component that is created as a class and thus
which can inherit fields and methods via `super` from the `React.Component`
class. This is necessary for handling props and configuring state.

A simple component, in contrast, is a function, not a class. These are used for
what we can call static or 'dumb' components, i.e they just output content and
data, they don't have reactive state. This is why they are also sometimes called
**functional stateless components**.

Simple components can however take props. In fact props are just like arguments
that you pass to a function. When you write a simple component, your parameters
are props.

Here's an example of a simple component that doesn't take any props

```jsx
function PageHeader() {
  return (
    <header>
      <h1>Site Title</h1>
    </header>
  );
}
```

We can safely use arrow functions with simple components. So the same component
could be written:

```jsx
const PageHeader = () => {
  return (
    <header>
      <h1>Site Title</h1>
    </header>
  );
};
```

Now adding a prop:

```jsx
const PageHeader = (props) => {
  return (
    <header>
      <h1>{props.sitename}</h1>
    </header>
  );
};
```

Then, in JSX we would apply the component with:

```jsx
<PageHeader sitename="The name of the site" />
```

> When we are using simple (functional) components we don't need to use
> `this.props` . `this` is only required with classes. As a simple component is
> a function we just say `props` .

It's worth noting in passing that you don't **have** to use functions for simple
components. You can achieve the same outcome with a class and it won't generate
an error. But it requires more code and complexity than is actually needed for
the job:

```jsx
class PageHeader extends React.Component {
  render() {
    return (
      <header>
        <h1> {this.props.siteName} </h1>
      </header>
    );
  }
}

export default PageHeader;
```


title: Cherry_picking
last_modified: 2024-10-18 18:55:56
body:
# Cherry-picking a commit

Cherry-picking is the act of selecting a specific commit or set of commits and
applying them to a different branch. It allows you to extract a change or a
series of changes from one branch and apply them to another branch without
merging the entire branch.

It can also be used to apply a series of commits that are not sequential in a
branch to another branch in a specific order.

Cherry-picking can sometimes result in conflicts, especially if the changes
you're trying to apply conflict with changes in the destination branch. In such
cases, you'll need to resolve the conflicts manually before completing the
cherry-pick process.

## Syntax

Suppose you have two branches: `main` and `feature`. You want to apply the
changes from the commit with hash `xyx` from the `main` branch to the `feature`
branch.

First, switch to the `feature` branch:

```
git checkout feature
```

Next, cherry-pick the commit from the `main` branch:

```
git cherry-pick xyz
```

This will apply the changes from the commit with hash `xyz` from thee `main`
branch to the `feature` branch. This will create a new SHA on `feature` (pqr)
but the changes will be identical.

![](/img/cherry-pick.svg)

The benefit is that you only take the select changes you want, you are not
merging the whole `main` branch into feature.

Note that you can also cherry-pick multiple commits by specifying their hashes
separated by spaces:

```
git cherry-pick abcdefg hijklmn opqrst
```

## Limitations

- You don't have to just cherry-pick locally, you can also cherry-pick from a
  [remote tracking branch](Remote_tracking_branches.md).
- You cannot cherry-pick merge commits since these commits do not implement a
  set of changes, they are connecting commits.

## Use case

The time when I have cherry-picked is when a commit has been reverted via
GitHub. This typically happens on the `main` branch when breaking changes have
been merged and we want to undo this by reverting back to the previous commit,
from before the problematic commit was merged in.

In this scenario, you will want to start from the reverted `main` branch and
then cherry-pick the breaking commit. You can then fix the bug and keep an
accurate record of the whole history.


title: React_useContext
last_modified: 2024-10-18 18:55:56
body:
# `useContext`

We use React's Context API to enable us to easily share stateful data between
all levels of an application without having to use repetitious 'prop-drilling'
at a component level.

This works best with data that is global by definition, such as theme parameters
or access authorisation. Context should not be used when standard and proximate
compositional methods and prop-passing are sufficient.

## Providers and consumers

The Context API preceded the introduction of hooks in React 16.8 and it still
underpins context management in hooks, although the syntax is simplified.

The process is as follows:

- Initiate a context
- Create a parent `Provider` component that owns the data that will be passed
  down
- Create child `Consumer` components that receive the data of the parent.

We will demonstrate using a set of styles as the context that we want to pass
around our app.

```jsx
const style = {
  border: "2px solid dodgerblue",
  background: "lightblue",
  color: "dodgerblue",
};
```

Le's initiate a context:

```jsx
const StyleContext = React.createContext();
```

Now that we have our data and have initialized a context, we can apply it to our
app components:

```jsx
<StyleContext.Provider value={style}>...</StyleContext.Provider>
```

This is the parent element of the context environment. This stores the
contextual data as a prop. Next we need to make a component that acts as the
consumer of this data. Let's create this component and call it `Child` for
simplicity:

```jsx
const Child = () => {
  return (
    <StyleContext.Consumer>
      {(value) => (
        <div style={value}>
          <p>
            I'm a <b>child</b>. I <b>consume</b> of the data my parent provides.
          </p>
        </div>
      )}
    </StyleContext.Consumer>
  );
};
```

The contents of this component are wrapped in tags that reference the specific
context (`StyleContext`) and the role that the component plays: `Consumer`.

We are taking the `value` prop owned by `StyleContext.Provider` and passing it
to the wrapping component of `Child` as a `style` tag. This means that `Child`
will display these styles.

The final step is just to insert our `<Child />` components beneath the parent
component, e.g.:

```jsx
<StyleContext.Provider value={style}>
  <Child />
  <Child />
</StyleContext.Provider>
```

## `useContext` hook

The hook removes the need to explicitly declare `Provider` and `Consumer`
components; their role becomes more implicit.

To demonstrate let's use a different example. We are going to have a single
integer as the data context, `42`.

First invoke and intialize the Context API, just as before:

```jsx
const NumberContext = React.createContext(42);
```

Next, we just need to create our provider component. We don't have to worry
about a consumer since this is handled implicitly by the invocation of the hook

```jsx
const Context = () => {
  const data = useContext(NumberContext);
  return <Typography>{data}</Typography>;
};
```

Then, in our code we just insert the `Context` component:

```jsx
<Context>...</Context>
```

## Updating context state

In the examples above we have only been consuming state that is owned by the
provider however in most scenarios you will also want to update the state from a
consumer. This is best achieved by combining `useContext` with a reducer and is
detailed in [Application state management](Application_state_management_with_React_hooks.md).


title: Voltage_sources
last_modified: 2024-10-18 18:55:56
body:
# Voltage sources

The following phenomena are the main sources that we use to generate voltage:

- friction
- magnetism
- chemicals
- light
- heat
- pressure

> In each case, energy in one state is transferred into energy as current. No
> energy is lost or gained, it simply changes its form.

### Magentism (electrical generators)

Magnetism is used as the voltage source in electrical generators and is by far
the most common method of producing powerful and large currents at scale.

If a conductive wire is passed through a magnetic field voltage will be produced
so long as there is motion between the magnetic field and the conductor. A
**generator** is a device that generates current in this manner. Generators
themselves need to be powered. They can be powered by steam from a nuclear power
plant, water, wind, coal or other fossil fuels.

#### AC/DC

Depending on how it is wired, a generator can produce **directed current** (DC)
or **alternating current** (AC):

- **Directed current**

  - The electrons flow in only one direction

- **Alternating current**
  - The electrons flow in one direction and then the other

### Chemicals (cells and batteries)

The chemical creation of current is the physics behind
[batteries](Cells_and_batteries.md). Chemical current production produces
currents on a smaller and less industrial scale than generators.

A chemical cell consists in two dissimilar metals such as copper and zinc. We
call these the **electrodes**. They are immersed in a salt, acid or alkaline
solution. We call these the **electrolytes**. The electrolyte pulls the free
electrons from the copper electrode which leaves it imbalanced with a positive
charge. The zinc electrode attracts the free electrons from the electrolyte
giving it a negative charge, thus a difference of potential is achieved.

### Light (photovoltaic cells)

Solar energy can be converted to electrical energy through solar panels which
are large collections of **photovoltaic cells**.

When the surfaces of these cells are exposed to light, it dislodges electrons
from their orbits around the surface atoms of the cell material. For each cell
this only produces a very small amount of energy, therefore large quantities
must be used.


title: Additive_inverse_property
last_modified: 2024-10-18 19:10:47
body:
# Additive inverse property

**Let $a$ represent any member of $\mathbb{Z}$. Then there is a unique member of
$\mathbb{Z}$ $-a$ such that:**

$$ a + (-a) = 0 $$

The sum of a number and it's negative (called **the additive inverse**) is
always zero.


title: User_agent
last_modified: 2024-12-20 11:05:59
body:
# User agent

_User agent_ is the technical term for a web browser. So named because it acts
on behalf of the user.

When a browser makes a request to a web server it includes a header value called
`User-Agent` that describes the browser.


title: Batch_processing
last_modified: 2024-11-12 07:34:48
body:
# Batch processing

With modern computer systems programs can be executed continuously and as
needed. With earlier computers (e.g. mainframes or mini-computers that were
shared by multiple users throughout an organisation) operating on this basis
would be expensive and would squander resources. It would also be inefficient
because computers needed time to warm up and cool down between operations.

Batch processing meant waiting until the required data for the operation met a
certain volume or threshold and then running the job. This way all the computer
resources were used at once instead repeatedly over an extended period.

Running operations in batch rather than in real-time also meant you could time
when you used the computer, running your jobs during off-peak hours when more
resources would be available. Particularly beneficial during the era of
time-sharing.


title: Relation_between_kernel_and_CPU
last_modified: 2024-10-18 18:55:56
body:
# Relation between the kernel and CPU

It can be confusing to understand how the kernel and CPU interact with one
another. Whilst it is true to say the kernel mediates between the hardware and
user processes, this led me to think that the kernel was somehow 'over and
above' the actions of the CPU. This is wrong and if you think about it, how
could this be since any process, kernel included, requires the processor? The
kernel is executed by and loaded into the CPU just like any other instruction in
the
[fetch, decode, execute cycle](Fetch_decode_execute.md)
of the CPU.

However as a process, the kernel is the 'first amongst equals' given that it is
the core embodiment of the operating system. At boot time, the kernel is
injected into memory and at this point the CPU _looks to this address_ in memory
in order to source its first instruction. That's how the kernel gets going. It
is the first instruction that the CPU fetches and this is what allows the kernel
to play its mediatory role. However most of the fetch, decode, execute cycles of
the CPU take place independently of the kernel.

![](/img/kernel-cpu-interaction.svg)

> Fetch decode and execute refer to processor pipeline stages. They occur
> automatically as part of normal processor operation, the kernel doesn’t
> generally have any direct control over how that happens...When the boot loader
> loads the kernel, it points the CPU’s program counter to an entry point in the
> kernel’s code. From there, the CPU will continue executing (fetching decoding
> and executing) kernel code until you point the program counter to a userspace
> program, where it will continue executing userspace code until an interrupt
> points the program counter back into kernel code. That’s basically what the
> CPU will be doing from boot up to shut down; switching between executing
> kernel code and executing userspace code
> ([Reddit]())

This is because of [context switching](), when the CPU is running its cycle, the
kernel is idle waiting for it to complete. Once control switches back to the
kernel it can then run its next duty which will be either process, memory or
device management or system calls. Then it will hand control over to either the
processor or user space.


title: Motherboard
last_modified: 2024-10-18 18:55:56
body:
# Motherboard

<img src="../img/motherboard-pi.jpg" width="400px"/>

The motherboard is the foundation of a computer. It allocates power and allows
communication to and between the
[CPU](CPU_architecture.md),
[RAM](Memory.md),
[harddisk](What_are_disks.md) and all other hardware
components.

It is a printed circuit board and is always the largest board within the
computer chassis.


title: Arrays
last_modified: 2024-10-18 18:55:56
body:
# Arrays

> Arrays are used both on their own and to implement many other data structures
> that place additional restrictions on how the data is manipulated.

## Algorithmic complexity

In terms of data retrieval arrays have a good runtime since retrieving an
element or storing an element takes constant time. Also an entire array takes up
O(n) space.

This only applies in the case of strict arrays that exist in strictly typed and
more advanced languages such as Java and C++. In JavaScript an array is really
closer to a list in other languages. That is to say, it's size (and of course
the types it holds) does not need to be known in advance or specified at all. In
stricter languages, you would cast the type for the array and specify its
length, for example:

```cpp
int anArray[10] = { 1, 2, 3, 4,  5, 6, 7, 8, 9, 10 }
```

Whilst storage and retrieval take place in constant time, deleting and inserting
elements through methods like `pop` and `shift` are more time consuming, since
the index of every item has to be updated in response.

## Random access

As we can access any element of the array at any time through index notation,
arrays offer random and non-sequential access. This is in contrast to stacks and
queues (where only the top/bottom can be accessed) and linked lists.


title: Williams_Tube_memory
last_modified: 2024-10-18 18:55:56
body:
# Williams Tube memory

- One of the early attempts to create RAM in computers based on the EDVAC
  stored-program architecture.

- Worked by displaying a grid of dots on a cathode-ray tube ("screen")

- Due to the way CRTs work, this creates a small charge of static electricity
  over each dot. The charge at the location of each of the dots is read by a
  thin metal sheet just in front of the display.

- Each dot position could be written to and read from and the pattern was
  constantly refreshed as the dots would fade over time.

![A Williams CRT tube](../img/williams-tube.jpg)

![Memory dot pattern from a Williams Tube](../img/williams-tube-dots.jpg)


title: Managing_environments_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Managing environments

With a full-scale Node application you will typically run three environments:

- Development
- Testing
- Production

## Accessing the current environment

To determine the current environment we can use the variable
**`process.env.NODE_ENV`** from the
[global process object](Process_object.md).
This works universally regardless of the kind of Node app we are building.

If you have not manually set up your environments, **`process.env.NODE_ENV`**
will return `undefined`.

### Setting the Node environment

#### For the session

`NODE_ENV` is a bash
[environment variable](Environmental_and_shell_variables.md)
like any other. So we can set it in the normal way:

```bash
export NODE_ENV=production
```

### In Express

In Express, there is a built in method for retrieving the current envrionment:
`app.get('env')`. Express will default to the development environment.

<p style="color:red">! How to keep Express and Node environment in sync?</p>

## Configuring environments

We use the third-party [Config](node-config)
package to manage different configurations based on the environment.

Once installed we set up a dedicated config directory with a structure as
follows:

```
config/
    default.json
    development.json
    production.json
```

For example:

```json
// default.json
{
  "name": "My Express app"
}
```

Then to utilise config variables:

```js
const config = require("config");
console.log("Application name:" + config.get("name"));
```

If we toggled the different environments, we would see different outputs from
the above code (assuming we had different config files in `/config` with
different names).

### Sensitive config data

We will need to store passwords, API keys and other kinds of authentication data
for our application. We obviously shouldn't store this data openly in our config
files since it would be made public.

We can do so securely by utilising
[environmental variables](Environmental_and_shell_variables.md)
alongside the config pacakage.

We create a file called `custom-environment-variables` (must be called this) and
map a property to an environmental environment we have already set.

Let's create an environmental variable for a password:

```bash
export APP_PASSWORD='mypassword123'
```

Then in our custom variable file:

```json
{
  "password": "APP_PASSWORD"
}
```

We can then safely reference this value in the course of our normal code:

```js
console.log(config.get("password"));
```

<p style="color:red">! But how would this be achieved in a production server?</p>

<p style="color:red">! And how could we do this programmatically at the start of a local development session without manually setting each environment variable in the terminal?</p>


title: Dependency_injection
last_modified: 2024-10-18 18:55:56
body:
# Dependency injection

Dependency injection is an object-oriented design pattern that allows for the
decoupling of dependencies between objects making code more maintainable,
testable and modular.

The basic idea is to resist having any class (C) depend on the specific
implementation details of any other class to which it sustains a dependency (D).
If we can abstract the implementation of D, this makes it easier to swap-out and
change C's dependencies later on without having to re-write C as a result of
changes to D.

This is where interfaces become very helpful because they are schematic
representations of the main methods in a given class (basically their names,
params and return value). As long as this is kept consistent in D when changes
are made, you avoid conflicts when changes or refactorings are made to D.

## Example

In the example to follow we will have two classes:

- `ConsoleLogger`
  - This will simply log something and be a dependency for the class below

* `UserService`
  - This will depend on `ConsoleLogger`

First we define an interface for the dependency:

```ts
interface ILogger {
  log(message: string): void;
}
```

So this is a class that has a single method `log` which receives a `message`
string as an argument and returns a side-effect.

Now we'll implement this class:

```ts
class ConsoleLogger implements ILogger {
  log(message: string): void {
    console.log(message);
  }
}
```

Now we create a class that depends on it:

```ts
class UserService {
  private logger: ILogger;

  constructor(logger: ILogger) {
    this.logger = logger;
  }

  createUser(username: string): void {
    // ... (some logic to create a user)
    this.logger.log(`User created: ${username}`);
  }
}
```

We can see that the constructor references the `Logger` interface. Thus we
inject the dependency when instantiating `UserService`:

```ts
// First implement our earlier class that matches the `Logger` in its shape:
const logger: ILogger = new ConsoleLogger();

// Then pass it as a dependency:
const userService: UserService = new UserService(logger);
userService.createUser("John Doe");
```


title: Hexadecimal_number_system
last_modified: 2024-10-18 18:55:56
body:
# Hexadecimal number system

Hexadecimal is the other main number system used in computing. It works in
tandem with the [binary number system](Binary_number_system.md) and provides an
easier and more accessible means of working with long sequences of binary
numbers.

## Hexadecimal place value

Unlike denary which uses base ten and binary which uses base two, hexadecimal
uses base 16 as its place value.

> Each place in a hexadecimal number represents a power of 16 and each place can
> be one of 16 symbols.

## Hexadecimal values

The table below shows the symbols comprising hexadecimal alongside their denary
and binary equivalents:

| Hexadecimal | Decimal | Binary |
| ----------- | ------- | ------ |
| 0           | 0       | 0000   |
| 1           | 1       | 0001   |
| 2           | 2       | 0010   |
| 3           | 3       | 0011   |
| 4           | 4       | 0100   |
| 5           | 5       | 0101   |
| 6           | 6       | 0110   |
| 7           | 7       | 0111   |
| 8           | 8       | 1000   |
| 9           | 9       | 1001   |
| A           | 10      | 1010   |
| B           | 11      | 1011   |
| C           | 12      | 1100   |
| D           | 13      | 1101   |
| E           | 14      | 1110   |
| F           | 15      | 1111   |

This table shows the raw value of each hexadecimal place value:

| $16^{3}$ | $16^{2}$ | $16^{1}$ | $16^{0}$ |
| -------- | -------- | -------- | -------- |
| 4096     | 256      | 16       | 1        |

## Hexadecimal prefix

The custom is to prefix a hexadecimal number with `0x` to indicate that the
number is hexadecimal.

## Converting hexadecimal numbers

Using the previous table we can convert hexadecimal values to decimal.

For example we can convert `1A5` as follows, working from right to left:

$(5 \cdot 1 = 5) + (A \cdot 16 = 160) + (1 \cdot 256 = 256) = 421$

The process is quite easy: we get the n from $16^{n}$ based on the position of
the digit and then multiply this by the value of the symbol (1,2,...F):

$$
  16^{n} \cdot 1,2,...F
$$

As applied to `0x1A5`:

| $16^{3}$               | $16^{2}$              | $16^{1}$                   | $16^{0}$            |
| ---------------------- | --------------------- | -------------------------- | ------------------- |
| $1\cdot 16^{3} = 4096$ | $1\cdot 16^{2} = 256$ | $A (10)\cdot 16^{1} = 160$ | $5\cdot 16^{0} = 5$ |

Another example for `0xF00F`:

$(15 \cdot 4096 = 61440) + (0 \cdot 256 = 0) + (0 \cdot 16 = 0) + (15 \cdot 1 = 15) = 61455$

## Using hexadecimal to simplify binary numbers

Whilst computers themselves do not use the hexadecimal number system (everything
is binary), hexadecimal offers advantages for humans who must work with binary:

1. It is much easier to read a hexadecimal number than long sequences of binary
   numbers
2. It is easier to quickly convert binary numbers to hexadecimal than to convert
   binary numbers to decimal

Look at the following equivalences

| Number system   | Example 1           | Example 2           |
| --------------- | ------------------- | ------------------- |
| **Binary**      | 1111 0000 0000 1111 | 1000 1000 1000 0001 |
| **Hexadecimal** | F00F                | 8881                |
| **Decimal**     | 61,455              | 34,945              |

It is obvious that a pattern is maintained between the hexadecimal and binary
numbers and that this pattern is obscured by the decimal conversion. In the
first example the binary half-byte `1111` is matched by the hexadecimal `F00F`.

Mathematically comparing hex `F` and binary `1111`:

$$
  \textsf{1111} = ((1 \cdot 2^{3}) + (1 \cdot 2^{2}) + (1 \cdot 2^{1}) + (1 \cdot 2^{0})) \\
  = 8 + 4 + 2 + 1 \\
  = 15
$$

$$
  \textsf{F} = 15 \cdot 16^{0}  \\
  = 15
$$

![](/img/hexadecimal-to-bytes.svg)

> Every four bits (or half byte) in binary corresponds to one symbol in
> hexadecimal. Therefore **a byte can be easily represented with two hexadecimal
> symbols, a 16-bit number can be represented with four hex symbols, a 32-bit
> number can represented with eight hex symbols and so on.**


title: MongoDB_connection
last_modified: 2024-11-04 14:26:19
body:
# MongoDB connection

```js
const mongoose = require("mongoose");

mongoose..connect("mongodb://127.0.0.1/[databse_name]");

const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    tags: [String],
    data: Date,
    isPublished: Boolean,
    price: Number
})

const Course = mongoose.model("Course", courseSchema);

async function getCourses(){
    return await Course
        .find({isPublished: true, tags: "backend"})
        .sort({name: 1})
        .select({name: 1, author: 1});
}
```


title: Application_Layer_of_Internet_Protocol
last_modified: 2024-10-18 18:55:56
body:
# Application Layer of the Internet Protocol

The final, topmost layer of the Internet Protocol suite.

![Data at the Application Layer](../img/application-layer-data.png)

The Application Layer is where we get to the protocols that describe the
behaviour of applications. All the preceding lower levels are effectively
**plumbing that enables applications to do the things they want accross the
internet**.

Whereas the lower levels facilitate communication accross the internet, the
Application Layer is concerned with achieving a specific task once the ability
to communicate is assured.

Application Layer protocols include HTTP, the Simple Mail Transfer Protocol
(SMTP), and FTP.


title: Structuring_Express_applications
last_modified: 2024-10-18 18:55:56
body:
# Structuring Express applications

In general, the following application structure works well:

```
\
    routes\
    models\
    middlewear\
    config\
    public\
  index.js

```

- **`routes/`**

  - This should house all our RESTful API endpoints for a given resource which
    we define as a module. For instance if we are handling API requests to
    `/api/courses/` we would have a module at `/routes/courses.js`

- **`models/`**
  - Here we define our database schemas: definitions for the structure of the
    data objects we want to return from the database.
  - In the case of Mongo we would have a file for each of our Mongoose models
    which will belong to an overall collection of which there are document
    instances.
  - Our model files should map onto our route modules; there should generally be
    at least one model file for each module. The model stands as an abstract
    representation of the data that we will be handling with our request paths
    in the routes file.


title: Network_protocols
last_modified: 2024-10-18 18:55:56
body:
# Network protocols

Protocols are agreed standards specifying and governing communication between
nodes on a [network](Network_fundamentals.md).

Network protocols are typically _layered_. The implmentation of a network layer
is a _stack_.

Stacks enshrine encapsulation: not every layer has to be directly concerned with
every other layer. Only adjacent layers that interface with each other need to
be in contact.

A prime example of a layered network stack is the
[internet_protocol_suite](Internet_fundamentals.md).


title: v8
last_modified: 2024-10-18 18:55:56
body:
# v8

The v8 module is useful for providing information about the resource-usage of
your Node.js apps, such as memory usage and capacity.


title: Compile_from_source
last_modified: 2024-10-18 18:55:56
body:
# Compile package from source

1. Clone the repo from GitHub
2. `cd` into the repo
3. Run `makepkg -c`

## Remove compiled package

1. If `build` dir still exists for package try running `make uninstall`.
2. Reinstall the package and run `make uninstall`
3. Locate the installed package in `/usr/local/bin` and run `sudo rm -rf`


title: Intersection_types_in_TypeScript
last_modified: 2024-10-18 18:55:56
body:
# Intersection types

Like union types, intersection types allow us to combine the properties of
existing primitive and custom types to make composites.

### Creating an intersection

Say you have the following three types:

```ts
type IConcert = {
  date: number;
  location: string;
  band: string;
};

type IConference = {
  date: number;
  location: string;
  keynoteSpeaker: string;
};

type IMeeting = {
  date: number;
  location: string;
  agenda: string[];
};
```

Each type corresponds to a different event and has two properties in common with
the other events: `date` and `location`.

Rather than repeat these properties for each individual type, we could create a
general `IEvent` type and apply this as an intersection to each of the
individual event types:

```ts
// The common event type
type IEvent = {
  date: number;
  location: string;
};
```

```ts
// The intersection

type IConcert = IEvent & {
  band: string;
};

type IConference = IEvent & {
  keynoteSpeaker: string;
};
```

> In the case of interfaces, instead of using `&` we would write
> `interface IConcert extends IEvent`

### Alternative method

There is another equivalent way of intersecting the types. We could first define
`IConcert` and `IConference` as their own types (without `extends` or `&`) and
then intersect with, e.g., type IConcert = SelfStandingConcertType & IEvent.

### Benefits of intersections

- It is more concise and we do not repeat ourselves needlessly
- Common properties can be modelled **in one place** which makes updates and
  changes much easier: we do not have to change multiple type declarations, just
  change the 'master' type that is intersected with the variants.
- It is more readable: we can see which properties are unique to the type
  without having to parse repeated properties.

## Set theory: understanding errors

With intersections we literally use the & operator which discloses that the
logic is equivalent to logical AND: a member of the intersection must have the
properties of both types. In the case of primitive values this is impossible or,
more accurately, it results in an empty set because, for example, `string` and
`boolean` do not share any common values. This means you will get an error if
you assign an intersection type to a value that does not have all the features
of each custom type in the intersection.


title: Adding_documents_to_a_Mongo_collection
last_modified: 2024-10-18 18:55:56
body:
# Adding documents to a collection

We have our database (`playground`) and collection (`courses`) established. We
now need to add documents to our collection. We will do this via a function
since this will be an asynchronous process:

```js
const pythonCourse = new Course({
  name: "Python Course",
  author: "Terry Ogleton",
  tags: ["python", "backend"],
  isPublished: true,
});

async function addCourseDocToDb(courseDocument) {
  try {
    const result = await courseDocument.save();
    console.log(result);
  } catch (err) {
    console.error(err.message);
  }
}

addCourseDocToDb(nodeCourse);
```

When we run this, we call the `save` method on the Mongoose schema. We will then
have the Mongo document outputted to the console:

```
{
  name: 'Python Course',
  author: 'Terry Ogleton',
  tags: [ 'python' ],
  isPublished: true,
  _id: new ObjectId("62f4ac989d2fec2f01596b9b"),
  date: 2022-08-11T07:15:36.978Z,
  __v: 0
}
```

This will also be reflected in Compass:

![](/img/mongo-doc-added.png)


title: Test_values_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Test values in Bash

`test` is a built-in command that is used to compare values or determine whether
something is the case.

We can use the command `test` but it is more common to test a condition
implicity by using square brackets. The square brackets are an alias for `test`.
We use this alias when we use `IF` logic.

When we run a test the result we get back is a return status of a `0` or a `1`.
`0` indicates that the test was a success and `1` means failure. (Bear in mind
this is in contrast to most all other programming languages.)

If we run a test in the command line we won't get a `0` or a `1` or back, there
will just be silence from the shell. We can explicitly invoke the return value
with variable `$?`, e.g:

```bash
[ -d ~ ] # is the home directory a directory?
echo $?
0   # yes

[ -d /bin/zsh ] # is this binary a directory?
echo $
1  # no
```

## Test structures

Many tests can be run with flags as a shorthand like we saw above:

### File operators

```
-a FILE        True if file exists.
-d FILE        True if file is a directory.
-e FILE        True if file exists.
-h FILE        True if file is a symbolic link
-s FILE        True if file exists and is not empty.
-N FILE        True if the file has been modified since it was last read.
```

### String operators

```
-z STRING      True if string is empty.
-n STRING      True if string is not empty.
```

## Differences between comparing numbers and strings

- `=` is reserved for comparing strings
- For numbers we use, e.g, `[ 4 -lt 5 ]`

## Negation

We can negate a test condition with `!`:

```bash
[ ! 4 -lt 3 ]; echo $?
0
```

## Running process if test succeeds or fails

We can use the following structure to run a process if a test condition obtains:

```bash
[[ -d ~ ]] && echo "/home is a directory"
```

## Extended test: `[[...]]`

When we use **double brackets** we are using _extended_ `test`.

The extended test supports the standard `test` comparisons and adds other
features:

- The use of Boolean operators:
  ```
  [[ -d ~ || -a /bin/mash ]]; echo $?
  ```

### Using regular expressions

Extended test also allows us to use regular expressions as part of our test
conditions. In order to test against a regular expression we use `=~` as the
comparison operator.

```bash
[[ "thomas" =~ t.* ]]; echo $?
```

Here the test succeeds because "thomas" begins with "t" followed by any other
character.

## Further examples

**Test if a character exists in two strings**

```bash
string1="hello"
string2="world"
char="l"

if [[ "$string1" == *"$char"* ]] && [[ "$string2" == *"$char"* ]]; then
    echo "Character '$char' exists in both strings."
else
    echo "Character '$char' does not exist in both strings."
fi
```

> Note: this syntax can also be used to test if a given element exists in an
> [array](Lists_and_arrays_in_Bash.md).


title: Create_timed_systemd_job
last_modified: 2024-10-18 18:55:56
body:
# Create timed `systemd` job

To use systemd to run a bash script at 11am each day, you can create a new
systemd service file. Here is an example of what the service file might look
like:

```
[Unit]
Description=Run My Script

[Service]
Type=simple
ExecStart=/bin/bash /path/to/my_script.sh

[Install]
WantedBy=default.target
```

Save this file to `/etc/systemd/system/my_script.service`.

Then you can use systemd to schedule the script to run at 11am each day by
creating a new systemd timer file. Here is an example of what the timer file
might look like:

```
[Unit]
Description=Run My Script Daily at 11am

[Timer]
OnCalendar=*-*-* 11:00:00

[Install]
WantedBy=timers.target
```

Save this file to `/etc/systemd/system/my_script.timer`

Then you can enable and start the timer with the following commands:

```
sudo systemctl enable my_script.timer
sudo systemctl start my_script.timer
```

This will run the script at 11am everyday You can check the status of the timer
with the following command:

```
sudo systemctl status my_script.timer
```


title: Environmental_and_shell_variables
last_modified: 2024-10-18 19:13:04
body:
# Environmental and shell variables

## Important!

To understand the difference between environmental and shell variables know
that:

- You can spawn child shells from the parent shell that is initiated when you
  first open the terminal. To do this just run `bash` or `zsh` .
- This is a self-contained new instance of the shell. This means:
  - It **will have** access to environmental variables (since they belong to the
    parent / are global)
  - It **will not have** access to any shell variables that are defined in the
    parent.
- **How do you get back to the ‘upper’ parent shell?** Type `exit` .
- Note that:
  - Custom (user-created) shell variables **do not** pass down to spawned shell
    instances, nor do they pass up to the parent
  - Custom (user-created) environment variables do pass down to spawned shell
    instances but do not pass up to the parent. They are lost on `exit` .

Q. What methods are there for keeping track of, preserving, and jumping between
spawned instances? Is this even possible or do they die on `exit` .

## Questions, research

1. If you create a variable manually I guess it won’t make it to any config
   file. How would you create a persistent var that is added to the `.bashrc`
   and thus which would be initialised on every session? Is this where the path
   comes in?
1. What methods are there for keeping track of, preserving, and jumping between
   spawned instances? Is this even possible or do they die on `exit` ?

## What is the shell environment and what are environment variables?

- Every time that you interact with the shell you do so within an
  **environment**. This is the context within which you are working and it
  determines your access to resources and the behaviour that is permitted.

- The environment is an area that the shell builds every time that it starts a
  session. It contains variables that define system properties.

- Every time a [shell session](Shell-sessions-e6dd743dec1d4fe3b1ee672c8f9731f6)
  spawns, a process takes place to gather and compile information that should be
  available to the shell process and its child processes. It obtains the data
  for these settings from a variety of different files and settings on the
  system.

- The environment is represented by strings comprising key-value pairs. For
  example:

  ```bash
  KEY=value1:value2
  KEY="value with spaces":"another value with spaces"
  ```

  As the above shows, a key can have multiple related values. Each one is
  demarcated with a `:` . If the value is longer than a single word, quotation
  marks are used.

- The keys are **variables**. They come in two types: **environmental
  variables** and **shell variables:**

  - Environmental variables are much more permanent and pertain to things like
    the user and his path (the overall session)
  - Shell variables are more changeable for instance the current working
    directory (the current program instance)

Variables can be created via config files that run on the initialisation of the
session or manually created via the command line in the current session

## What are shell variables useful for?

Some deployment mechanisms rely on environmental variables to configure
authentication information. This is useful because it does not require keeping
these in files that may be seen by outside parties.

More generally they are used for when you will need to read or alter the
environment of your system.

## Viewing shell and environmental variables

To view the settings of your current environment you can execute the `env`
command which returns a list of the key-value pairs introduced above. Here are
some of the more intelligible variables that are returned when I run this
command:

```bash
SHELL=/usr/bin/zsh
DESKTOP_SESSION=plasma
HOME=/home/thomas
USER=thomas
PWD=/home/thomas/repos/bash-scripting
PATH=/home/thomas/.nvm/versions/node/v16.8.0/bin:/home/thomas/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin
```

However if you want to target a specific viable you need to invoke `printenv`
with the relevant key, for example:

```bash
printenv SHELL
# SHELL=/usr/bin/zsh
```

Note that `env` and `printenv` do not show all the shell variables, only a
selection. To view all the shell variables along with the environmental
variables use `set` .

## Creating, exporting and deleting variable shell and environment variables

- You set shell variables using the same syntax you would within a script file:

  ```bash
  TEST_SHELL_VAR="This is a test"
  set | grep TEST_SH
  TEST_SHELL_VAR='This is a test'

  # We can also print it with an echo, again exactly as we would with a shell script
  echo S{TEST_SHELL_VAR}
  ```

- We can verify that it is not an environmental variable based on the fact that
  following does not return anything:

  ```bash
  printenv | grep TEST-SH
  ```

- We can verify that this is a shell variable by spawning a new shell and
  calling it. Nothing will be returned from the child shell.

- You can upgrade a shell variable to an environment variable with `export` :

  ```bash
  export TEST_SHELL_VAR
  # And confirm:
  printenv | grep TEST_SH
  TEST_SHELL_VAR='This is a test'
  ```

- We can use the same syntax to create new environment variables from scratch:

  ```bash
  export NEW_ENV_VAR="A new var"
  ```

### Using config files to create variables

You can also add variables to config files that run on login such as your user
`.bashrc` / `.zshrc` . This is obviously best for when you want the variables to
persist and be accessible within every
[shell session](Shell-sessions-e6dd743dec1d4fe3b1ee672c8f9731f6).

## Important environmental and shell variables

### `PATH`

A list of directories that the system will check when looking for commands. When
a user types in a command, the system will check directories in this order for
the executable.

```bash
echo ${PATH}
# /home/thomas/.nvm/versions/node/v16.8.0/bin:/home/thomas/.local/bin:/usr/local/sbin:/usr/local/bin:
# /usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin
```

For example, if you wish to use `npm` commands globally (in any directory) you
will need to have the requisite Node executable in your path, which you can see
above.

### `SHELL`

This describes the shell that will be interpreting any commands you type in. In
most cases, this will be bash by default, but other values can be set if you
prefer other options.

```bash
echo ${SHELL}
# /usr/bin/zsh
```

### `USER`

The current logged in user.

```bash
echo ${USER}
# thomas
```

### `PWD`

The current working directory.

```bash
echo ${PWD}
# /home/thomas
```


title: Basics_of_web_components
last_modified: 2024-10-18 18:55:56
body:
# Basics of Web Components

Web Components are custom HTML elements like those we create with frameworks
like React and Angular but which are native to HTML and the DOM and therefore do
not require any special compilation or libraries.

- Designed to be interoperable with normal HTML
- Designed to be interoperable with component frameworks like React
- Designed to be highly modular and reusable
- Utilise the shadow DOM which is like the virtual DOM but native to the browser
  and invocable through plain JavaScript. A bit like an iFrame within the
  "light" DOM and helps greatly with style-scoping.

## Example of composing a web component:

```js
// MyComponent.js
class MyComponent extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<h1>Hello world</h1>`;
  }
}

customElements.define("my-component", MyComponent);
``;
```

```html
<!-- index.html -->
<my-component></my-component>
```

## Resources

[A complete introdution to Web Components]()


title: Creating_a_Docker_image
last_modified: 2024-10-18 18:55:56
body:
# Creating a Docker image

We create a new image with `docker build...`

The key components of a build:

- A Dockerfile
- An asset directory (the **build context**) containing the Dockerfile and all
  resources needed for the build.

## Syntax

Here is an example of a Dockerfile that builds a container for running a Python
app:

```Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.8-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

```

### Main syntax explained

| Keyword   | Role                                                                                                                                                                                                                                                                   |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #         | Lines starting with '#' are comments, providing explanations or context for the Dockerfile.                                                                                                                                                                            |
| `FROM`    | Specifies the base image used to build the new image. In this case, it's using the official Python 3.8 slim image.                                                                                                                                                     |
| `WORKDIR` | Sets the working directory for any subsequent instructions in the Dockerfile. Here, it's set to '/app'. Everything after a `WORKDIR` line, all instructions will be executed in this directory. If it doesn't exist, Docker will create it. Can have multiple.         |
| `COPY`    | Copies files or directories from the source (in this case, the current directory) to the destination (in this case, '/app') within the Docker image. The source is the build context. We are copying from the build context to the container when we use this keyword. |
| `ADD`     | Same as `COPY` but can be passed a tarball or a URL                                                                                                                                                                                                                    |
| `RUN`     | Executes a command and commits the result as a new layer in the image. In this example, it installs packages specified in the 'requirements.txt' file using pip.                                                                                                       |
| `EXPOSE`  | Informs Docker that the container listens on the specified network ports at runtime. In this case, port 80.                                                                                                                                                            |
| `ENV`     | Sets an environment variable in the image. In this example, the variable 'NAME' is set to 'World'.                                                                                                                                                                     |
| `CMD`     | Specifies the command to run when the container starts. Here, it runs 'app.py' using Python. Note that there can only be one CMD instruction in a Dockerfile.                                                                                                          |
| `USER`    | The default user will be `root`. This is not good for security. Have to choose a distribution image that allows you to change user. For example: `USER: nobody:nogroup`. Ubuntu allows for this.                                                                       |
| `LABEL`   | Metadata that you want to add to the image to be viewable when image is inspected, e.g. `LABEL maintainer=tactonbishop@gmail.com`                                                                                                                                      |

### Another example

The following Dockerfile creates a frontend React application:

```Dockerfile
# Use the official Node.js image as the base image
FROM node:14-alpine

# Set the working directory to /app
WORKDIR /app

# Copy the package.json and package-lock.json files
COPY package*.json ./

# Install dependencies
RUN npm ci

# Copy the rest of the application code
COPY . .

# Expose the port the app will run on
EXPOSE 3000

# Start the React development server
CMD ["npm", "start"]
```

### Two modes of `RUN`: shell and exec

The RUN command in a Dockerfile has two forms: the "exec" form and the "shell"
form. Both forms are used to execute commands during the build process, but they
have different syntax and behavior.

Exec form is written as `RUN ["executable", "param1", "param2", ...]`. This form
executes the command directly without invoking a shell. As a result, shell
processing features like environment variable substitution, pipes, and redirects
are not available. It is the preferred form when you need to run a command
without relying on shell behavior or when you want to avoid shell-related
issues, such as variable substitution or command injection.

Shell form is written as `RUN command param1 param2 ....` This form executes the
command within a shell, which is /bin/sh -c on Linux and cmd /S /C on Windows.
It allows for shell processing, enabling environment variable substitution,
pipes, redirects, and other shell features. This form is preferred when you need
to use shell features or when you want to chain multiple commands together.

## Environmental variables

> ENV instructions in a Dockerfile are used to define environment variables that
> can be accessed by the processes running inside the container. These variables
> can be used to configure the behavior of the application, pass parameters, or
> store sensitive information like API keys.

```Dockerfile
# Use an official Node.js runtime as a parent image
FROM node:14-alpine

# Set the working directory to /app
WORKDIR /app

# Copy package.json and package-lock.json into the container
COPY package*.json ./

# Install any needed packages specified in package.json
RUN npm ci

# Copy the rest of the application code
COPY . .

# Set environment variables
ENV PORT=8000
ENV API_KEY=my_secret_key

# Expose the port the app will run on
EXPOSE 8000

# Run the app
CMD ["npm", "start"]
```

In this example, two environment variables are defined: PORT and API_KEY. These
variables can be accessed in the application code using process.env.PORT and
process.env.API_KEY in Node.js, for example.

To override the environment variables defined in the Dockerfile when running the
container, you can use the -e flag followed by the variable name and its new
value in the docker run command:

```sh
docker run -e PORT=8080 -e API_KEY=new_secret_key -p 8080:8000 <image_name>
```


title: 653c0b1d_host_protocols_of_ARPANET
last_modified: 2024-10-25 09:01:54
body:
# 653c0b1d_host_protocols_of_ARPANET

The responsibility for enabling communication between nodes fell to the hosts,
not the [IMPs](e470bf3d_IMPs_in_the_ARPANET.md). At the lowest level (equivalent
to the [link layer](Link_Layer_of_Internet_Protocol.md) in the subsequent
internet?), this consisted in moving raw bits between hosts regardless of what
specific type of data they encoded.

In the book (_Where Wizards Stay Up Late_), there is a great description by
analogy:

> Some water out of the tap is used for making coffee, some for washing dishes,
> some for bathing. The pipe and the faucet do not care about this; they convey
> the water regardless.


title: Components_props_hooks_in_React
last_modified: 2024-10-18 18:55:56
body:
# Components and props with hooks

As of React 16.8 a class component can be expressed using a function-based hook.

A class component:

```jsx
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
```

The same component expressed as a hook:

```jsx
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
```

To output this component we use the same standard JSX syntax and pass the prop
as an attribute of the JSX element:

```jsx
<Welcome name="Thomas" />
```

## How hooks are rendered

1. We call `ReactDOM.render()` with the `<Welcome name="Thomas" />` element.
   (This would typically be nested within a root `App` component; it wouldn't be
   directly passed to the parent render function.)
2. React calls the `Welcome` component with `{name: 'Thomas'}` as the props.
3. Our `Welcome` component returns a `<h1>Hello, Thomas</h1>` element as the
   result.
4. React DOM efficiently updates the DOM to match `<h1>Hello, Thomas</h1>`.

## Function components must be pure functions

> All React components must act like pure functions with respect to their props

This means that functions should not attempt to change the inputs they receive
as parameters. They must always return the same result for the same inputs:

```jsx
function sum(a, b) {
  return a + b;
}
```

```jsx
function withdraw(account, amount) {
  account.total -= amount;
}
```

The reason for this is that **props are read-only** and we pass props to
function components.

We change components by using state, not by mutating props. This is consistent
with React's
[principle of the immutability of elements](Elements-992594b9cd2e483c85cddddffeb16f11).


title: Rules_for_operations_on_like_and_unlike_terms
last_modified: 2024-10-19 09:57:20
body:
# Rules for operations on like and unlike terms

## Addition

### Like terms

> Sum the absolute values and add the negative sign afterwards.

$$
\\begin{split}
-4 + -3
\\ = 4 + 3
\\ = -7
\\end{split}
$$

### Unlike terms

> Subtract smaller from larger amount and then affix the sign of the larger
> amount to the sum.

#### Negative plus positive

$$
\\begin{split}
-8 + 5
\\ = 8 - 5
\\ = 3
\\ = -3
\\end{split}
$$

#### Positive plus negative

$$
\\begin{split}
4 + -1
\\ = 4 - 1
\\ = 3
\\end{split}
$$

## Subtraction

### Like terms

> Turn the operator and second negative into a plus sign and execute as an
> addition.

$$
\\begin{split}
-4 - -3 =
\\ = -4 + 3
\\ = -1
\\end{split}
$$

### Unlike terms

#### Positive subtract negative

> Turn the negative after the operator to a positive. (Same as previous.)
>
> $$
> \\begin{split}
> 2 - -3 =
> \\ = 2 + 3
> \\ = 5
> \\end{split}
> $$

#### Negative subtract positive

> Start at the negative value and count backwards on the number-line

$$
-2 - 3 = -5
$$

## Multiplication

### Like terms

> The product of two negative numbers will always be a positive number.

$$
-15 \cdot -3 = 45
$$

### Unlike terms

> The product of a positive and a negative number will always be a negative
> number.

$$
-3 \cdot 5 = -15
$$

## Division

**Division follows the same rules as multiplication.**

### Like terms

> The quotient of two negative numbers will always be a positive number.

$$
-15 / -3 = 5
$$

### Unlike terms

> The quotient of a positive and a negative number will always be a negative
> number.

$$
-15 / 3 = -5
$$


title: python_advent_learnings
last_modified: 2024-10-18 18:55:56
body:
# Python advent learnings

### Construct paths without hard-coding absolute path

```py
puzzle_input_path = os.path.join(os.path.dirname(__file__), "data/test_input.txt")

```

### Read file by line and store in variable

```py
puzzle_input_path = os.path.join(os.path.dirname(__file__), "data/test_input.txt")

def getPuzzleInput(file_path):
    with open(file_path, "r") as file:
        return [line.strip() for line in file]


puzzle_input = getPuzzleInput(puzzle_input_path)

```

### Conditional tests for members of arrays

Check that all elements are greater than zero:

```py
if all(element >= 0 for element in array):
    print('All elements greater than 0')
```

Check if any element is less than 0:

```py
if any(element < 0 for element in array):
    print('There is an element that is less than 0')
```

### Check for substring:

```py
text = "latest test"
if "test" in text:
    return True
```

### Control flow in loop

```py
for counter_values in games:
    colour = counter_values[1]
    count = int(counter_values[0])
    if colour in initial_values.keys() and count > initial_values[colour]:
        break
else:
    valid_games_count += game_number
```

The use of the `else` clause here is a special feature of Python. The `else`
clause after a `for` loop will normally only execute when the loop has finished
iterating over the list, but not when the loop is terminated by a `break`
statement.

The `else` clause is executed if the `for` loop completes normally. If the
`break` statement is executed (i.e., if any count in `counter_values` is greater
than the corresponding count in `initial_values`), the `for` loop is terminated
and the `else` clause is skipped.

Here the combination of a `for` loop and the `break` statement creates
`if, else` logic. If the break condition is not reached, then the `else` block
runs for every iteration of the loop.

### Multiple loop in list comprehension

```py
games = [item.strip().split() for game in games for item in game.split(",")]
```


title: Text_manipulation_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Text manipulation

## Sorting strings: `sort`

If you have a `.txt` file containing text strings, each on a new line you can
use the sort function to quickly put them in alphabetical order:

```bash
sort file.txt
```

Note that this will not save the sort, it only presents it as a standard output.
To save the sort you need to direct the sort to a file in the standard way:

```bash
sort file.txt > output.txt
```

### Options

- `-r`
  - reverse sort
- `c`
  - check if file is already sorted. If not, it will highlight the strings which
    are not sorted

## Find and replace: `sed`

The `sed` programme can be used to implement find and replace procedures. In
`sed`, find and replace are covered by the substitution option: `/s` :

```bash
sed ‘s/word/replacement word/’ file.txt
```

This however will only change the first instance of word to be replaced, in
order to apply to every instance you need to add the global option: `-g` .

As sed is a stream editor, any changes you make using it, will only occur within
the standard output , they will not be saved to file. In order to save to file
you need to specify a new file output (using `> output.txt`) in addition to the
original file. This hasthe benefit of leaving the original file untouched whilst
ensuring the desired outcome is stored permanently.

Alternatively, you can use the `-i` option which will make the changes take
place in the source file as well as in standard input.

Note that this will overwrite the original version of the file and it cannot be
regained. If this is an issue then it is recommended to include a backup command
in the overall argument like so:

```bash
sed -i.bak ‘s/word/replacement word/’ file.txt
```

This will create the file `file.txt.bak` in the directory you are working within
which is the original file before the replacement was carried out.

### Remove duplicates

We can use the `sort -u` command can be used to remove duplicates:

```bash
sort -u file.txt
```

It is important to sort before attempting to remove duplicates since the `-u`
flag works on the basis of the strings being adjacent.

## Split a large file into multiple smaller files: `split`

Suppose you have a file containing 1000 lines. You want to break the file up
into five separate files, each containing two hundred lines. You can use `split`
to accomplish this, like so:

```bash
split -l 200 big-file.txt new-files
```

`split` will categorise the resulting five files as follows:

- new-file-aa,
- new-file-ab
- new-file-ac,
- newfile-ad,
- new-file-ae.

If you would rather have numeric suffixes, use the option `-d` . You can also
split a file by its number of bytes, using the option `-b` and specifying a
constituent file size.

## Merge multiple files into one with `cat`

We can use `cat` read multiple files at once and then append a redirect to save
them to a file:

```bash
cat file_a.txt file_b.txt file_c.txt > merged-file.txt
```

## Count lines, words, etc: `wc`

To count words:

```bash
wc file.txt
```

When we use the command three numbers are outputted, in order: lines, words,
bytes.

You can use modifiers to get just one of the numbers: `-l`, `-w` , `-b` .


title: a247fa9b_surveillance_capitalism_not_necessary
last_modified: 2024-12-01 19:34:56
body:
# a247fa9b_surveillance_capitalism_not_necessary

_Surveillance capitalism is neither a necessary development of information
capitalism nor a necessary product of digital technology or the internet. It is
a specifically constructed human choice, an unprecedented market form, an
original solution to an emergency, and the underlying mechanism through which a
new asset class is created on the cheap and converted to revenue._

_The Age of Surveillance Capitalism_ (2019): 91


title: Basic_model_of_the_operating_system
last_modified: 2024-10-18 18:55:56
body:
# Basic model of a nix operating system

We can abstract the Linux OS into three operational levels or tiers, from the
bottom up:

<dl>
<dt>User processes: user space</dt>
<dd>The running programs that the kernel manages. Also known as the user space which is the memory that the kernal assigns for user processes. Comprising:
<ul>
    <li>Graphical user interface</li>
    <li>Servers</li> 
    <li>Shell</li>    
  </ul>
<dt>Kernel: kernel space</dt>
</dd>
<dd>The core of the operating system. Software residing in memory that tells the CPU where to look for its next task. Acts as a mediator and primary interface between the hardware and the user processes. Known as kernel space: the memory that the kernel allocates for itself. Comprising:
  <ul>
    <li>System calls</li>
    <li>Process management</li> 
    <li>Memory management</li>    
    <li>Device drivers</li>    
  </ul>
</dd>
<dt>Hardware</dt>
<dd>The base: one or more CPUs and RAM memory performing computations and writing to memory. Comprising:
  <ul>
    <li>Processor (CPU)</li>
    <li>Main memory (RAM)</li> 
    <li>Disks</li>    
    <li>Network ports</li>    
  </ul>
</dl>

!! Add info on kernel mode and user mode
https://www.geeksforgeeks.org/user-mode-and-kernel-mode-switching/


title: Bash_file_exists
last_modified: 2024-11-17 15:07:20
body:
# Bash file exists

```bash
FILE_PATH="$PWD/foo/bar.json"
if [ ! -f "$FILE_PATH" ]; then
	echo -e "ERROR Graph file ( $FILE_PATH ) does not exist. Exiting."
	exit 0
fi
```


title: Role_of_unique_key_in_relational_databases
last_modified: 2024-10-18 18:55:56
body:
# Unique key

> Every table in a relational database should have a **unique key**. A unique
> key is one **field that uniquely identifies each record**.

This is essential for carrying out operations across database tables and for
creating and deleting database entires in accordance with the
[ACID principle](ACID_principle.md). It is also a safeguard: it means
you can always identify a record by itself and don't have to rely on generic
queries to identify it.

Sometimes you will have a dedicated field such as `UNIQUE_ID` for the unique
key. Other times you can use an existing field to fulfil that function. When an
existing, visible column is used as the unique key it is called the **primary
key**. Other times the unique key can be hidden from the table.

In both cases the following constraints **must be met:**

1. No two records can have the **same** primary key data
1. The primary key value should **never be reused**. Thus, if a record is
   deleted from the table, it should not be re-allocated to a new record.
1. A primary key value **must not be modified** once it has been created
1. A primary key **must have a value**; it cannot be `null`


title: Custom_React_hook_examples
last_modified: 2024-10-18 18:55:56
body:
# Custom hook examples

## Determine viewport width

### Hook

```js
// useViewportWidth.js
import { useEffect, useState } from "react";

export default function (viewportWidth) {
  const [matchesViewportWidth, setMatchesViewportWidth] = useState(false);

  useEffect(() => {
    const handleResize = () =>
      window.innerWidth < viewportWidth
        ? setMatchesViewportWidth(true)
        : setMatchesViewportWidth(false);

    window.addEventListener("resize", handleResize);

    // Call on initialization to determine initial width
    handleResize();

    // Clean-up listener to prevent memory leaks
    return () => window.removeEventListener("resize", handleResize);
  }, [viewportWidth]);

  return matchesViewportWidth;
}
```

### Unit test

```js
import useViewportWidth from "./useViewportWidth";
import { fireEvent } from "@testing-library/react";
import { act } from "react-dom/test-utils";
import { renderHook } from "@testing-library/react-hooks";

describe("useViewportWidth", () => {
  it("returns `true` when window resized to mobile viewport width", () => {
    // Arrange
    const { result } = renderHook(() => useViewportWidth(768));

    // Act
    act(() => {
      window.innerWidth = 500;
      fireEvent(window, new Event("resize"));
    });

    // Assert
    expect(result.current).toBe(true);
  });

  it("returns `false` when window resized to width greater than mobile viewport", () => {
    // Arrange
    const { result } = renderHook(() => useViewportWidth(768));

    // Act
    act(() => {
      window.innerWidth = 1058;
      fireEvent(window, new Event("resize"));
    });

    // Assert
    expect(result.current).toBe(false);
  });
})``;
```


title: Bluetooth
last_modified: 2024-10-18 18:55:56
body:
# Bluetooth

## Connect to devices with `bluetoothctl`

```bash
# Start bluetooth first
bluetoothctl power on
```

Then:

```bash
# Launch bluetoothctl
bluetoothctl
```

This initiates `[bluetooth] #` prompt. Then follow this sequence:

```bash
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# scan on
pair [device_code]
connect [device_code]
```


title: Dictionaries_in_Python
last_modified: 2024-11-16 13:30:17
body:
# Dictionaries in Python

Dictionaries are basically the Python equivalent of objects in JS.

Dictionaries:

- Are ordered (in contrast to JS)
- Are mutable
- Are indexed by a key which references a value
- Can be increased/decreased in length by adding/removing new members.

## Basic usage

Dictionaries are declared with `{...}`:

```python
cities = {
  'Wales': 'Cardiff',
  'England': 'London',
  'Scotland': 'Edinburgh',
  'Northern Ireland': 'Belfast',
  'Ireland': 'Dublin'
}

print(type(citites))
# <class 'dict'>
```

## Accessing entries

```python
print(cities['Wales'])
# Cardiff

print(cities.get('Ireland'))
# Dublin

print(cities.values())
# ['Cardiff', 'London', 'Edinburgh', 'Belfast', 'Dublin']

print(cities.keys())
# ['Wales', 'England', 'Scotland', 'Northern Ireland', 'Ireland']

print(cities.items())
# [('Wales', 'Cardiff'), ('England', 'London'), ('Scotland', 'Edinburgh'), ('Northern Ireland', 'Belfast'), ('Ireland', 'Dublin')]
```

## Predicates

```py
print('Wales' in cities)
# True

print('France' not in cities)
# True
```

## Looping

```py
for country in cities:
    print(country, end=', ')
    print(cities[country])

"""
Wales, Cardiff
England, London
Scotland, Edinburgh
Northern Ireland, Belfast
Ireland, Dublin
"""

for e in country.values():
    print(e)
```

## Updating values

```py
cities['Wales'] = 'Swansea'
print(cities)
```

## Removing values

```py
# Remove last item
cities.popitem()
print(cities)
# {'Wales': 'Cardiff', 'England': 'London', 'Scotland': 'Edinburgh', 'Northern Ireland': 'Belfast'}

# Remove specific entry by key

cities.pop('Northern Ireland')
print(cities)
# {'Wales': 'Cardiff', 'England': 'London', 'Scotland': 'Edinburgh'}

del cities['Scotland']
print(cities)
{'Wales': 'Cardiff', 'England': 'London'}
```

## Containers as values

```py
seasons = {
'Spring': ('Mar', 'Apr', 'May'),
'Summer': ('June', 'July', 'August'),
'Autumn': ('September', 'October', 'November'),
'Winter': ('December', 'January', 'February')}

print(seasons['Spring'])
print(seasons['Spring'][1])

"""
('Mar', 'Apr', 'May')
Apr
"""
```

## Merging two Dictionaries

Two separate dictionaries can be merged into a single dictionary with shared
properties with this shorthand:

```python
merged_dictionary = dictionary_one | dictionary_two

```

## Spreading dictionary properties

In JavaScript we can spread values from one object into a new object that
inherits those values with `{...spreadValues, newProperty: 'foo'}`.

This can be achieved in Python with the `|` union operator, e.g:

```python
text_base = {"height": 1, "font": font}

heading_text = text_base | {
    "bg": colors["accent"],
    "fg": colors["background"],
}

```


title: Negative_exponents
last_modified: 2024-10-18 19:17:49
body:
# Negative exponents

When calculating the exponents of a negative number the answer will always will
be positive:

$$
-5^2 = 25
$$

This confused me but it was because I was thinking of it in terms of
$-5 \cdot 5$ when in fact it is $-5 \cdot -5$ and when two negative numbers are
multiplied the product is always negative.


title: DRAM_and_SRAM_memory
last_modified: 2024-10-18 19:12:33
body:
# DRAM and SRAM memory

There are two types of RAM memory: [SRAM and DRAM](./DRAM_and_SRAM_memory.md).

### DRAM

DRAM uses capacitors to create the memory cell:

> a **capacitor** is an electronic component that stores electrical energy in an
> electrical field. A device which can accumulate and release electrical charge.

In a DRAM cell, each bit of data is stored as a charge in a capacitor. The
presence of charge represents a '1' bit and the absence of charge represents a
'0' bit. Each of these cells is paired with a [transistor](Transistors.md) that
controls the reading and writing of data.

However capacitors lose [charge](Current.md) over time due to leaks. As a result
DRAM is memory that needs to be refreshed (recharged) frequently. For this
reason and because it only uses one transistor and capacitor per bit, DRAM is
the less expensive form of volatile memory.

### SRAM

SRAM (Static Random Access Memory) is also volatile memory but its electronical
implementation is different. Unlike DRAM it doesn't use capacitors. Consequently
the transistors do not leak or need to be refreshed, hence why SRAM is _static_
and DRAM is _dynamic_.

SRAM uses [flip flops](Flip_flops.md) to store the bits. It also uses multiple
transistors per bit. This makes it faster than DRAM but more expensive. DRAM is
at least ten times slower than SRAM.


title: Appending_to_files_in_Python
last_modified: 2024-10-25 09:28:57
body:
# Appending to files in Python

```py
file = open("example.txt", "a")
file.write('Add something to the end of the file')
file.close()
```

```py
with open("example.txt", "a"):
    file.write("Add something to the end of the file")
file.close()
```


title: Prime_factorization
last_modified: 2024-10-18 19:19:08
body:
# Prime factorisation

Prime factorisation is the activity of expressing a composite number as the
unique product of [prime numbers](Primes%20and%20composites.md). There are two
main approaches to this:

- - factor\* trees
- repeated division by two

> **Factor trees:** we take a number $n$ and break it down into two factors of
> $n$. We then repeat this process with the resulting factors working
> recursively until the numbers we are left with are primes.

![Untitled Diagram-Page-1.drawio.png](Untitled%20Diagram-Page-1.drawio.png) _The
prime factors of 27 are 2, 3, 3_

it doesn't matter which products we choose as the interim factors, we should
always reach the same outcome:
![Untitled Diagram-Page-3.drawio 1.png](Untitled%20Diagram-Page-3.drawio%201.png)

![Untitled Diagram-Page-2.drawio.png](Untitled%20Diagram-Page-2.drawio.png)


title: Exponents
last_modified: 2024-10-18 18:55:56
body:
## Equivalent equations

> Two equations are equivalent if they have the same solution set.

We know from the distributive property of multiplication that the equation
$a \cdot (b + c )$ is equivalent to $a \cdot b + a \cdot c$. If we assign values
to the variables such that $b$ is equal to $5$ and $c$ is equal to $2$ we can
demonstrate the equivalence that obtains in the case of the distributive
property by showing that both $a \cdot (b + c )$ and $a \cdot b + a \cdot c$
have the same solution:

$$ 2 \cdot (5 + 2) = 14 $$

$$ 2 \cdot 5 + 2 \cdot 2 =14 $$

When we substitute $a$ with $2$ (the solution) we arrive at a true statement
(the assertion that arrangement of values results in $14$). Since both
expressions have the same solution they are equivalent.

## Creating equivalent equations

Adding or subtracting the same quantity from both sides (either side of the $=$
) of the equation results in an equivalent equation.

### Demonstration with addition

$$ x - 4 = 3 \\ x -4 (+ 4) = 3 (+ 4) $$

Here we have added $4$ to each side of the equation. If $x = 7$ then:

$$ 7 - 4 (+ 4) = 7 $$

and:

$$ 3 + 4 = 7 $$

### Demonstration with subtraction

$$ x + 4 = 9 \\ x + 4 (-4) = 9 (-4) $$

Here we have subtracted $4$ from each side of the equation. If $x = 5$ then:

$$ 5 + 4 (-4) = 5 $$

and

$$ 9 - 4 = 5 $$


title: Binary_encoding
last_modified: 2024-10-18 18:55:56
body:
# Binary encoding

We know that everything going on in a computer is the manipulation of binary
digits. Thus all data must ultimately reduce to binary numbers manipulated
through logic circuits.

_Encoding_ is the process of establishing a correspondence between sets of
binary numbers and sets of symbols that are representative of a given type of
data. For certain fundamental data types, for example alphanumeric characters
and colours, there are agreed standards of encoding such that, for example, that
`111111` (binary) and `3F` (hex) always corresponds to the character `?`. The
reverse is obviously _decoding_: deriving the data/ symbol from the binary
format.

> An encoding system maps each symbol to a unique sequence of bits. A computer
> then interprets that sequence of bits and displays the apppropriate symbol to
> the user.

The length of the binary number (sometimes called the _word length_)
corresponding to 8-bit, 16-bit, 32-bit etc. that is used to represent a given
data set is determined by the number of variations that you require to capture
the entire range of the dataset:

> An $n$-bit binary system can encode $2^n$ different things

For example, say we know that there are 18 levels to a computer game. To encode
a reference for each level we would need a binary number that is capable of at
least 18 total variations. In this instance a 32-bit ($2^{5}$ ) number would be
best because the next smallest (16-bit) would not be sufficient. Our levels
would have representations as follows:

```
00001 (1)
00010 (2)
00011 (3)
00100 (4)
...
```

## Related points

Think about when you open a file format in a text editor that cannot decode it.
For example trying to open a Word document in VSCode. The mangled letters it
displays is the encoded binary data. When you open the file in Word, the
decoding is applied and it resembles what you would expect.

When we save a file, the different file extensions denote different formats and
these are encoding formats. For example if you save an image file as `.png`
rather than `.jpg`, you are applying a different encoding algorithm to the data
that compresses the raw binary data in a different way.


title: Retrieve_data_from_SQL_table
last_modified: 2024-10-18 18:55:56
body:
# Retrieve data from table with SQL `SELECT` statement

> Select data from the database. The data returned is stored in a result table
> called the **result-set**.

_A table named `models`:_

| modelId | name                 | cores | releaseDate |
| ------- | -------------------- | ----- | ----------- |
| 2       | Raspberry Pi Model B | 2     | 2022-11-19  |
| 3       | Raspberry Pi Model C | 4     | 2022-11-25  |
| 4       | MacBook Pro M2       | 9     | 2022-03-18  |

## Basic usage

```sql
SELECT name FROM models
```

We can pass in a comma-separated **list of fields**:

```sql
SELECT name, releaseDate FROM models
```

## With parameters

### `WHERE`

The `WHERE` clause specifies a search criterion. The `WHERE` clause should
always be last in the syntax. The clauses are always written in this order:
`FROM` followed by `WHERE`

```sql
SELECT name FROM models WHERE cores > 3
```

### Compound statements

Compound statements allow you to apply more filters to your clauses within an
SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by
using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` ,
`<=` ...)

Multiple clauses:

```sql
SELECT name, ram, release_date
FROM model
WHERE release_date > '2018-01-01' AND ram > 512;
```

More complex logic achieve with parentheses:

```sql
SELECT name, cores, release_date
FROM model
WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
```

## Transform returned data

We can apply **ordering** to the return data

```sql
SELECT name FROM models ORDER BY name, cores
SELECT name FROM models ORDER BY name, cores DESC
```

> `ORDER BY` always comes last, after the selection and any filtering clauses
> but _before_ a `WHERE` clause

## Paginate

We can break our returned data into blocks with `LIMIT`

```sql
LIMIT 5 -- Return first five items
LIMIT 5,5 -- Return first five items from the sixth row
```


title: Aggregate_functions_in_SQL
last_modified: 2024-10-18 18:55:56
body:
# Aggregate functions in SQL

Aggregate functions enable us to return data about the data that a table holds.
For example the sum of a given column or its average.

## Count return with custom variable

```sql
SELECT COUNT(*) AS total_sales
FROM SALES
```

## Sum

```sql
SELECT SUM(price) as total_value
FROM sales
```

## Average

```sql
SELECT AVG(price) as average_income
FROM sales
```

## Applying aggregate function with sorting applied

```sql
SELECT COUNT(*) AS total_sales
FROM sales
GROUP BY employee_id
```


title: Fundamental_Theorem_of_Arithmetic
last_modified: 2024-10-18 19:14:32
body:
# Fundamental Theorem of Arithmetic

> Every integer greater than one is either a prime number itself or is product
> of a unique combination of primes.

This is also known as the **Unique Factorisation Theorem**.

'Unique' means that there is not more than one way to derive the whole number.
Once you reduce the factorisation to primes, there can only be one set of
numbers that results in the target number.

For example, $24$ has the following factors: ${12, 24}$ and $6, 4$ but these are
composite numbers. The unique factorisation combination for 24 is $2, 2, 3$.


title: Effective_logging_in_Git
last_modified: 2024-10-18 18:55:56
body:
# Effective logging in Git

| Root command      | Variant      | Output                                                   |
| ----------------- | ------------ | -------------------------------------------------------- |
| `git log`         | filename.txt | List the commits that changed the given file             |
| `git log --patch` | filename.txt | Show the diff changes for each commit for the given file |
| `git log --patch` | null         | Show the diff changes for each commit for all files      |


title: Functions
last_modified: 2024-10-18 18:55:56
body:
# Functions

Continuing from the other examples of React Typescript, we could do standard
listing function, like:

```tsx
<ul>
  {people.map((person) => {
    return <li>{person.name}</li>;
  })}
</ul>
```

But it's neater to do it with a function defined within the `List` component:

```tsx
const renderList = (): JSX.Element[] => {
  return people.map((person) => {
    return (
      <li>
        <div>{person.name}</div>
        <div>{person.age}</div>
      </li>
    );
  });
};
```

And then change the eariler list to a function invocation:

```tsx
    <ul>{renderList()}<ul>
```


title: Sets_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Sets in Python

- They are **unordered**
- You can increase/decrease their length by adding/removing new members
- They **do not allow duplicate members**
- **Can only hold immutable objects**

> Sets are denoted with `{...}`

## Basic usage

```python
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket)  # show that duplicates have been removed
print(len(basket))
# {'apple', 'pear', 'banana', 'orange'}
# 4
```

## Looping through sets

```python
for item in basket:
    print(item)

"""
apple
pear
banana
orange
"""
```

## Check for membership

```python
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print('apple' in basket)
# True
```

## Remove items from set

> `remove` will raise an error if the specified item does not exist, `discard`
> will not

```python
basket.remove('apple')
basket.discard('apricot')
print(basket)
# {'pear', 'banana', 'orange'}

basket.clear()
print(basket)
#set

```

## Add items to a set

```python
basket.add('apricot')
print(basket)
# {'apricot', 'pear', 'banana', 'orange'}
```

## Start with empty set

To declare an empty set you cannot just do:

```py
my_set = {}
```

You have to use a constructor:

```py
my_set = set()
```

## Apply unions and intersections

```python
s1 = {'apple', 'orange', 'banana'}
s2 = {'grapefruit', 'lime', 'banana'}
print('Union:', s1 | s2)
# Union: {'apple', 'orange', 'grapefruit', 'lime', 'banana'}

print('Intersection:', s1 & s2)
# Intersection: {'banana'}


print('Difference:', s1 - s2)
# Difference: {'orange', 'apple'}

print('Symmetric Difference:', s1 ^ s2)
#Symmetric Difference: {'apple', 'orange', 'grapefruit', 'lime'}

```


title: File_descriptors
last_modified: 2024-10-18 18:55:56
body:
# File descriptors

File descriptors are shorthand for `stdin`, `stdout` and `stderr`:

| File descriptor | Name            | Common abbreviation |
| --------------- | --------------- | ------------------- |
| 0               | Standard input  | `stdin`             |
| 1               | Standard output | `stdout`            |
| 2               | Standard error  | `stderr`            |

They are typically used when you want to
[redirect](Redirection_in_Bash.md) the output of the
standard/input /output/error somewhere, e.g a file or as input to another
program. A classic case is `[some_command] > /dev/null 2>&1`

They are all technically "files" which are open and which append themselves to
every process that can run in the shell. For any command or program that you
run, you will be able to access `0`, `1` and `2` for them. In this way they are
similar to variables like
[`$0`](Passing_arguments_and_options_to_Bash_scripts.md#passing-arguments)
and
[`$@`](Passing_arguments_and_options_to_Bash_scripts.md#passing-arguments).
They have a universal meaning within the context of the shell runtime.


title: Network_hosts
last_modified: 2024-10-18 19:18:24
body:
# Network hosts

A network **host** or **node** is a single computing device attached to a
![network](Network_fundamentals.md)

Hosts can act as servers or clients, or both.

## Server

A network server is a host that listens for inbound network connections and
provides services to other hosts. Examples include web and email servers.

## Client

A network client is a host that makes outbound connections and requests servcies
from network servers.


title: Half_adder_and_full_adder
last_modified: 2024-10-18 18:55:56
body:
# The half adder and full adder

## Binary arithmetic

The half adder and full adder are components of digital circuits that enable us
to carry out binary addition. Using adders and half adders we can add two binary
numbers together. Adders are a type of [integrated circuit]() comprising certain
[logic gates](Logic_gates.md) where the arrangement allows for the
representation of the addition of bits.

### Example addition

Consider the following binary addition:

```
  c_1
0   0   1   0
0   0   1   1
_____________
0   1   0   1
```

How does the calculation proceed? Moving from the right-most column:

- $1 + 0 = 1$ hence the sum of the first column (the binary 1 coumn) is $1$ with
  no carry
- Moving to the second column (the binary 2 column), $1 + 1 = 2$ however we do
  not have the digit "2" in binary, therefore we must bump the place value by
  one place and carry this sum as a $1$ leaving a zero to mark the place value
- Thus the third column (the binary 4 column) has the calculation:
  $1 + 0 + 0 = 1$ with no carry.

### Bits

From the previous example we can identified the following repeated actions:

- For calculations of the form $1 + 0$ or $0 + 0$ there will be no carried digit
- For calculations of the form $1 + 1$ there will be a carried digit

In the context of adders the digits are bits. We distinguish three core bits by
their role in the calculation: the carry, the **least significant bit** and the
**most significant bit**. The least significant bit is the right-most digit in
the calculation. The most significant bit is the leftmost.

The two types of adders are distinguished by which bits of the calculation they
operate on. The half adder focuses on the least significant bit whereas the full
adder focuses on the most significant bit.

## Half adder

The half adder receives two bits (A and B) which are to be added together. It
outputs this value as the **sum bit**. If there is a bit to be carried to the
next column in the binary calculation this will be output as the **carry-out**
bit.

| A                            | B                             | S           | C_out             |
| ---------------------------- | ----------------------------- | ----------- | ----------------- |
| The first number to be added | The second number to be added | The sum bit | The carry-out bit |

The diagram below shows the circuit representation of a half-adder and an
example calculation. This calculation matches the ones column of the earlier
binary addition example: $0011 + 0010$.

![](/img/half-adder-new.png)

### Implementation with logic gates

If we think about it, the possible inputs and outputs of a half adder are highly
circumscribed:

- If the sum exceeds $1$, the sum bit will be $0$ and the carry-out bit will be
  $1$
- In all other cases the carry-out bit will be $0$. These other cases are when
  the sum bit is either $0$ or $1$, e.g: $1 + 0$ or $0 + 0$.

We can represent this with a simple truth-table:

| A   | B   | S   | C_out |
| --- | --- | --- | ----- |
| 0   | 0   | 0   | 0     |
| 0   | 1   | 1   | 0     |
| 1   | 0   | 1   | 0     |
| 1   | 1   | 0   | 1     |

We can see that the sum bit column replicates the truth-conditions of
[XOR](Logic_gates.md#xor-gate):

| P   | Q   | P V Q |
| --- | --- | ----- |
| T   | T   | F     |
| T   | F   | T     |
| F   | T   | T     |
| F   | F   | F     |

And the carry-out bit replicates the truth conditions of
[AND](Logic_gates.md#and-gate):

| P   | Q   | P & Q |
| --- | --- | ----- |
| T   | T   | F     |
| T   | F   | F     |
| F   | T   | F     |
| F   | F   | T     |

It is therefore possible to implement a half-adder with just these two logic
gates:

![](/img/half-adder-gates-three.png)

The digital circuit above has the same inputs and outputs as the half adder
diagram above.

<iframe src="https://circuitverse.org/simulator/embed/half-adder-67b14a9f-d1ed-4240-ab19-1d753f18a40d" style="border-width:; border-style: solid; border-color:;" name="myiframe" id="projectPreview" scrolling="no" frameborder="1" marginheight="0px" marginwidth="0px" height="400" width="600" allowFullScreen></iframe>

## Full adder

As the half adder only calculates the least significant bit, it is not
sufficient by itself to complete a binary addition; it cannot account for
movements in binary place value. To carry out full calculations it must be
supplemented with the full adder.

The full adder takes in three inputs and has two outputs. It is identical to the
half-adder apart from the fact that one of its inputs is **carry-in**. This is
equivalent to the value that is designated as **carry-out** in a half adder. It
is an incoming value that is the product of a previous operation that resulted
in a carry-out. This is added together with the full adders own two inputs (A
and B) and like the half adder, generates a sum bit and a carry-out bit.

| A                            | B                             | C_in                     | S                      | C_out                        |
| ---------------------------- | ----------------------------- | ------------------------ | ---------------------- | ---------------------------- |
| The first number to be added | The second number to be added | The incoming carried bit | The sum bit (A+B+C_in) | The carry-out bit (A+B+C_in) |

![](/img/full-adder-new.png)

The diagram above is equivalent to the calculation taking place in the fours
column. It has received a carry from the twos column ($1 + 1$ results in $1$ as
a carry) and then adds this together with its own inputs ($0$ and $0$).

```
  c_1
0   0   1   0
0   0   1   1
_____________
0   1   0   1
```

### Implementation with logic gates

When it comes to implementing the full adder with logic gates we can allow
ourselves greater abstraction as we already have the half adder to work with. We
don't need to create a half adder from scratch, we can reuse it.

We are adding three bits: $1$, $0$ and $0$. This can be achieved with two half
adders:

- One half adder (HA1) for the sum of $0 + 0$
- One half adder (HA2) for the sum of $(0 + 0) + 1$ (the previous sum plus the
  third bit)

The sum of HA1 ($0 + 0$) is passed in to the B input on HA2 and the $1$ is
passed in as the A input of HA2. This gives us $1$ as the sum bit of HA2.

At this point we have completed the addition and have successfully added the
three bits: $1$, $0$, and $0$ to get $1$ as ths sum. However we also have to
account for the fact that the addition may result in its own carry-out bit. What
if the inputs were $1, 1, 0$ for example?

<iframe src="https://circuitverse.org/simulator/embed/full-adder-674f8ddf-c5aa-42fa-9c0f-4349ffabe723" style="border-width:; border-style: solid; border-color:;" name="myiframe" id="projectPreview" scrolling="no" frameborder="1" marginheight="0px" marginwidth="0px" height="400" width="700" allowFullScreen></iframe>


title: Binary_units_of_measurement
last_modified: 2024-10-18 18:55:56
body:
# Binary units of measurement

A single place or symbol in a decimal number is called a **digit**. For example
the number 343 is a number containing three digits. A digit can be any one of
the ten numerals through 0-9.

The equivalent entity in the
[binary number system](Binary_number_system.md)
is the **bit**. For example the binary number 110 has three bits. A bit can only
have one of two values in contrast to a digit which can have one of ten values.
These values are 0 and 1.

## Sequences of bits

### Informational complexity

The informational complexity of a single digit is much larger than a single bit:
it can represent one of 10 states whereas a bit can only represent one of two
states.

We can think of how much data can be stored in a number in terms of the total
number of unique arrangements of bits or digits. With this in mind, compare a
two digit digital number to a two bit binary number. For the decimal number each
digit can represent one of ten states, hence the total number of unique states
is equal to $2^{10} (1024)$:

With the binary number we have $2^{2} (4)$, giving us far fewer possible unique
states. They are so few we can easily list them:

```
00
01
10
11
```

### Bytes

In order to express larger binary numbers and greater complexity we work with
sequences of bits.

The standard **base sequence** of bits is called a **byte**. This is a binary
number comprising **eight bits**. For example the number `11001110` is a byte
equivalent to 206 in decimal.

A byte allows for a complexity of up to 256 possible states: $2^{8} = 256$

## Metric units: kilobytes, megabytes etc

Having established that the core quantity of information is the byte, the
convention is to apply the
[standard metric prefixes](Prefixes_for_units_of_electrical_measurement.md)
to the byte to establish units:

| Prefix | Symbol | Expression as base ten exponent | Value             | English word |
| ------ | ------ | ------------------------------- | ----------------- | ------------ |
| Terra- | T      | $10^{12}$                       | 1,000,000,000,000 | trillion     |
| Giga-  | G      | $10^9$                          | 1,000,000,000     | billion      |
| Mega-  | M      | $10^6$                          | 1,000,000         | million      |
| Kilo-  | k      | $10^3$                          | 1,000             | thousand     |

Hence 2MB is two million bytes, 4kb is four thousand bytes etc.

Whilst the metric prefixes are conventionally used to refer to aggregates of
bytes, they are only approximate values due to the fact that metric is base ten
whereas bytes are base two. Hence 1MB is not 1,000,000 bytes it is 1,048,576
bytes.

This is usually fine as a shorthand but an accurate representation of byte
values is as follows:

| Prefix | Symbol | Expression as base two exponent | Value             | English word |
| ------ | ------ | ------------------------------- | ----------------- | ------------ |
| Terra- | T / Ti | $2^{40}$                        | 1,099,511,627,776 | trillion     |
| Giga-  | G / Gi | $2^{30}$                        | 1,073,741,824     | billion      |
| Mega-  | M / Mi | $2^{20}$                        | 1,048,576         | million      |
| Kilo-  | k / Ki | $2^{10}$                        | 1,024             | thousand     |

> A special IEEE standard was introduced to distinguish base two within the
> metric nomenclature: kibi, mebi, gibi etc but this was not widely adopted. The
> symbols for this are included above as they are sometimes used by Linux
> programs (Gi, Mi, Ki etc)


title: React_useEffect
last_modified: 2024-10-18 18:55:56
body:
# `useEffect`

`useEffect` should be used for any background process that does not arise as a
result of a user interaction or standard state change. The canonical example
would be dispatching a request to an API to retrieve data to display in a
component's initial render.

`useEffect` enshrines but also simplifies the
[lifecyle methods](Lifecycle_methods.md) that are used with
class-based React components.

## Demonstration

```jsx
const [workflowTitle, setWorkflowTitle] = useState("");
const [loading, setLoading] = useState(false);

useEffect(() => {
  const fetchWorkflowTitle = () => {
    axios
      .post(`${process.env.REACT_APP_ENDPOINT}/load-workflows`, {
        workflow_id: project_id,
        user_id: isAuth?.userId,
      })
      .then((res) => {
        setWorkflowTitle(res?.data?.meta.name);
      })
      .finally(() => setLoading(false))
      .catch((err) => {
        console.error(err);
      });
  };
  setLoading(true);
  fetchWorkflowTitle();
}, [project_id, isAuth]);
```

In this example we fetch some data from a REST API and store the response value
as state, which can then be accessed within our JSX template.

## Function placement

In the example, the function is declared inside of the `useEffect` hook and then
called. We do this to avoid adding the function to the dependency array, which
we couldn't do if we defined it outside of the hook, somewhere in the component.
If we did this, the function would run on every render by default and would be
recalled again because of its placement in the dependency array, which leads to
the 'too many rerenders' error.

An alternative would be to define it outside of the component itself but this is
difficult since it requires state from the component to run.

## Dependency array

Note the array that is the second argument to `useEffect`. This is the
**dependency array** and is how we manage the lifecycle of the side-effect.

- After the initial call on render, the function within the `useEffect` block
  will run any time one of the dependencies update. The dependency array
  typically refers to variables that are defined within the hook but can also
  contain references to variables outside of it.

- If you do not include the array, the effect runs on every render

- If you pass an empty array, the effect will only run once on the initial
  render

## Cleanup functions

The syntax of the `useEffect` hook also allows you to handle cleanup: something
you want to do when the component unmounts (another example of how this hook
recasts the traditional [lifecycle methods](Lifecycle_methods.md))
. In addition to running on unmount, the cleanup function will run before the
effect runs again (i.e. when it runs in response to a change in one of the
elements of the dependency araray). This is chiefly used to prevent
[memory leaks](Memory_leaks.md) and the
['update on unmounted component error'](React_errors.md#state-update-on-unmounted-component).

You do this by having a `return` clause after the main effect. Schematically:

```js
useEffect(() => {
  //  Run your effect;
  return () => {
    //   Put your cleanup function here
  };
}, [input]);
```

Here is an example of using a cleanup to cancel a subscription

```js
useEffect(() => {
  let isApiSubscribed = true;
  axios.get(API).then((response) => {
    if (isApiSubscribed) {
      // handle success
    }
  });
  return () => {
    isApiSubscribed = false;
  };
}, []);
```

## Resources

[Understanding the React useEffect cleanup function]()


title: With_open_in_Python
last_modified: 2024-10-25 09:47:03
body:
# With open in Python

We use the `open()` method to create a **file object** that allows us to read,
write and append to files.

The general syntax is as follows:

```py
file_object = open(<file_name>, <access_mode>)
```

`<file_name>` is a path to the file you want to read, create or modify. The
`<access_mode>` denotes the mode in which to open the file. The most frequently
used are:

- `r`
  - [read](Reading_files_in_Python.md)
- `w`
  - [write](Writing_to_files_in_Python.md)
- `a`
  - [append](Appending_to_files_in_Python.md)

When we have finished with an I/O operation, such as reading from or writing to
a file, we must call `file.close()` to terminate the process. This removes the
reference to the file from memory.

A more pythonic and concise way of reading files and closing them is to use
`with...as` syntax. When this phrasing is used, a self-contained context is
created for the I/O operation that closes the file automatically.

```py
with open('filename.txt', 'r') as file:
    contents = file.read()
    print(contents)
```


title: Corresponding_material_and_biconditional
last_modified: 2024-10-18 18:55:56
body:
# Corresponding material conditional to show validity

To demonstrate _truth-functional validity_ we have to construct a truth-table
which contains each of the premises and the conclusion and then review each row
to see if there is an assignment where both the premises and the conclusion are
true.

A simpler way to get the same result is to invoke the corresponding material
conditional. Here we concatenate the premises using conjunction and then join
them to the conclusion using the material conditional, which then becomes the
main connective. We then populate the truth table for this compound proposition.
If it is logically true, the argument is valid.

### Demonstration

We will demonstrate with the following set:

$$ \{ P \leftrightarrow Q, P \lor Q, P \land Q \} $$

| $P$ | $Q$ | $P \leftrightarrow Q$ | $P \lor Q$ |
| --- | --- | --------------------- | ---------- |
| T   | T   | T                     | T          |
| T   | F   | F                     | T          |
| F   | T   | F                     | T          |
| F   | F   | T                     | F          |

| $P$ | $Q$ | $(P \leftrightarrow Q) \land (P \lor Q)) \leftrightarrow (P \land Q)$ |
| --- | --- | --------------------------------------------------------------------- |
| T   | T   | T                                                                     |
| T   | F   | T                                                                     |
| F   | T   | T                                                                     |
| F   | F   | T                                                                     |

We see above that the main connective, the material conditional returns true for
every truth-functional assignment. In other words it is logically true.
Consequently the argument is valid

## Corresponding material biconditional

We can use the corresponding material biconditional as a shorthand for
demonstrating logical equivalence between two propositions.

For two putatively equivalent propositions $P$ and $Q$, $P$ and $Q$ are
logically equivalent if the compound proposition $P \leftrightarrow Q$ is
logically true.


title: DeMorgan's_Laws
last_modified: 2024-10-18 18:55:56
body:
# DeMorgan's Laws

DeMorgan's laws express some fundamental equivalences that obtain between the
Boolean
[connectives](Truth-functional_connectives.md).

## First Law

> The negation of a conjunction is logically equivalent to the disjunction of
> the negations of the original conjuncts.

$$
\lnot (P \land Q) \leftrightarrow \lnot P \lor \lnot Q
$$

The equivalence is demonstrated with the following truth-table

| $P$ | $Q$ | $ \lnot (P \land Q)$ | $ \lnot P \lor \lnot Q$ |
| --- | --- | -------------------- | ----------------------- |
| T   | T   | F                    | F                       |
| T   | F   | T                    | T                       |
| F   | T   | T                    | T                       |
| F   | F   | T                    | T ### Truth conditions  |

> The negation of a disjunction is equivalent to the conjunction of the negation
> of the original disjuncts.

$$
\lnot (P \lor Q) \leftrightarrow \lnot P \land \lnot Q
$$

| $P$ | $Q$ | $ \lnot (P \lor Q)$ | $ \lnot P \land \lnot Q$ |
| --- | --- | ------------------- | ------------------------ |
| T   | T   | F                   | F                        |
| T   | F   | F                   | F                        |
| F   | T   | F                   | F                        |
| F   | F   | T                   | T                        |


title: Tuples_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Tuples in Python

TODO: Exapand tuple notes - give more use cases

Tuples are one of the main data-structures or containers in Python. Tuples are
useful in cases where you want to group related data and ensure that it will not
change.

Tuples have the following properties:

- They are **ordered**
- They have a **fixed size**
- They are **immutable** and cannot be modified
- **Allow duplicate** members
- They are **indexed**

> In essence a tuple is a list that is immutable.

As with all containers in Python they permit any data type.

> Tuples are denoted with `(...)`

## Basic usage

```python
tup1 = (1, 3, 5, 7)
print(tup1[2])

# 5
"""
```

## Slicing

```python
tup1 = (1, 3, 5, 7)

print(tup1[1:3])
print(tup1[:3])
print(tup1[1:])
print(tup1[::-1])

"""
(3, 5)
(1, 3, 5)
(3, 5, 7)
(7, 5, 3, 1)
"""
```

## Looping

```python
tup3 = ('apple', 'pear', 'orange', 'plum', 'apple')
for x in tup3:
    print(x)

"""
apple
pear
orange
plum
apple
"""
```

## Useful methods and predicates

```python
tup3 = ('apple', 'pear', 'orange', 'plum', 'apple')

# Count instances of a member
print(tup3.count('apple'))
# 2

# Get index of a member
print(tup3.index('pear'))
# 1

# Check for membership
if 'orange' in tup3:
    print('orange is in the Tuple')

# orange is in the Tuple
```

## Nest tuples

```python

tuple2 = ('John', 'Denise', 'Phoebe', 'Adam')
tuple3 = (42, tuple1, tuple2, 5.5)
print(tuple3)

# (42, (1, 3, 5, 7), ('John', 'Denise', 'Phoebe', 'Adam'), 5.5)

```

// TODO: How to flatten a tuple?


title: Strategies_for_constructing_proofs
last_modified: 2024-10-18 18:55:56
body:
# Strategies for constructing proofs in propositional logic

## General strategy

- Break complex propositions into simpler sentences by using the elimination
  rules
- Recombine simple propositions into complex propositions using the introduction
  rules.

## Goal analysis

The approach above describes the general form of a proof but of course it will
not always work and there will be cases where the route to the desired
derivation is more circuitous. In these instances it is to best to combine this
general top level strategy with goal analysis.

Goal analysis is a [recursive](Recursion.md) strategy which
proceeds by using a 'goal' proposition to guide the construction of intermediary
derivations.

Assume that we want to show that an argument is
[valid](Validity_and_entailment.md#validity). Then our
ultimate goal is to derive the conclusion from the premises we are given. We
first ask ourselves: _which propositions if we could derive them, would allow us
to easily derive the conclusion_? (For example, these propositions might be two
simple propositions that when combined with
[Conjunction Introduction](Conjunction_Introduction.md) give us
the conclusion.) Deriving these propositions then becomes the new intermediate
goal.

If arriving at these propositions is not trivial, we then ask ourselves the
question again: _which propositions would permit us to derive the intermediary
propositions we need_? You keep working back in this manner until you reach a
base level. Then it is just a matter or working upwards from each set of derived
intermediary propositions until you reach the ultimate goal.

### Demonstration

Let's say we want to prove $(L \lor A) \land D$ from the propositions $\lnot N$
and $((\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N))$.

First, we consider what is the easiest possible way of achieving the proposition
$(L \lor A) \land D$. Clearly it is to separately derive each disjunct
($L \lor A$ and $D$) and then combine them with
[Conjunction Introduction](Conditional_Introduction.md). This
provides us with our first goal: to derive each of the separate conjuncts.

Let's start with $D$: where does it occur in the assumptions? It occurs in the
compound $(\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N)$, but only
in the first conjunct. We can get this simply but applying
[Conjunction Elimination](Conjunction%20Elimination.md).

So far we have:

![](/img/step1.png)

Now we just need to get $D$ from the proposition at line 3. This is easy since
we already have access to the consequent of the biconditional at line 1.
Therefore we can apply
[Biconditional Elimination](Biconditional_Elimination.md)) at line
3 to get $D$. We are now halfway there:

![](/img/step2.png)

Next we need to turn our attention to deriving $L \lor A$. How can we obtain $L$
? Well it is contained within the first conjunct of the assumption on line 2.
Again, we can get this through the application of
[Conjunction Elimination](Conjunction_Elimination.md). Now, how do
we get $L$ from $(\lnot N \rightarrow L)$? Well, we already have the antecedent
$\lnot N$ as an assumption on the first line, so we can use
[Conditional Elimination](Conditional_Elimination.md) to derive
$L$. These two steps give us:

![](/img/step3.png)

Now we need to get from $L$ to $L \lor A$. This is really straightforward
because by using
[Disjunction Introduction](Disjunction_Introduction.md)) we can
get from any sentence to a disjunction. Finally, having assembled all the
constituent parts of the conjunction that is the conclusion, we can combine them
with [Conjunction Introduction](Conjunction_Introduction.md) as we
had planned at the outset.

![](/img/step4.png)

### A further example

We will seek to prove the following:

$$
\{ \lnot L \leftrightarrow [X \land (\lnot S \lor B) ], (E \land C) \rightarrow \lnot L, (E \land R) \land C \} \vdash X \land (\lnot S \lor B)
$$

The requirements here could easily mislead us. We see that the target
proposition is a conjunction so we might think that the best strategy is to seek
to derive each conjunct and then combine them via
[Conjunction Introduction](Conjunction_Introduction.md)).

Actually, if we look more closely, there is a better approach. The target
proposition is contained in the first premise as the consequent to the
biconditional ($\lnot L \leftrightarrow [X \land (\lnot S \lor B)]$). A better
approach is therefore to seek to derive the antecedent ($\lnot L$) and then use
[Biconditional Elimination](Biconditional_Elimination.md) to
extract the target sentence which is the consequent.

![proof.png](proof.png)

## Proving theorems

When we are proving
[theorems](Theorems_and_empty_sets.md#theorems-and-empty-sets)
we do not have a set of assumptions to work from when constructing the proof. We
must derive the target sentence from the 'empty set' which is the target
sentence itself. It is therefore like a process of reverse engineering.

### Demonstration

_Prove:_ $\vdash (U \land Y) \rightarrow [L \rightarrow (U \land L)]$

Our strategy here is to identify the main connective in the proposition we want
to derive (the material conditional). We then assume the antecedent and attempt
to derive the consequent from it.

![](/img/theoremproof.png)

## A complex theorem proof

_Prove_ $\vdash (\lnot A \lor \lnot B) \leftrightarrow \lnot(A \land B)$

![](/img/dsfdsfsdfwe.png)

### Walkthrough

**Lines 1-12**

- Our auxiliary goal is to prove
  $\lnot (A \lor B) \rightarrow \lnot (A \land B)$.

- Our starting assumption is to a disjunction. Thus we can apply
  [Disjunction Elimination](Disjunction_Elimination.md) to show
  that our goal sentence $\lnot(A \land B)$ follows from each of the disjuncts
  ($\lnot A$ and $\lnot B$) in dedicated sub-proofs. If we can do this, we have
  the right to derive $\lnot (A \land B)$.

- In both cases($\lnot A \vdash \lnot (A \land B)$) and
  ($\lnot B \vdash \lnot (A \land B)$ we require another sub-proof to reach the
  target as there is no easy path available. So we derive a negation from
  $A \land  B$ so that we can negate it as $\lnot (A \land B)$.

- Having done this, we can discharge the
  [Disjunction Elimination](Disjunction_Elimination.md) sub-proofs
  and derive $\lnot (A \land B)$ from $\lnot A \lor \lnot B$

**Lines 13-26**

- Our auxiliary goal is to prove
  $\lnot (A \land B) \rightarrow \lnot A \lor  \lnot B$. This will require a
  different approach to the above because we are not working from a disjunction
  anymore, we have a negated conjunction.
- We will do this by assuming the negation of what we want to prove
  ($\lnot (\lnot A \lor \lnot B)$) and then apply
  [Negation Elimination](Negation_Elimination.md) to get
  $\lnot A \lor \lnot B$.
- This requires us to derive a contradiction. We get this on lines 23 and 24.
  This requires as previous steps that we have two sub-proofs that use
  [Negation Elimination](Negation_Elimination.md) to release $A$
  and $B$


title: Type_guarding_and_narrowing_in_TS
last_modified: 2024-10-18 18:55:56
body:
# Type narrowing and guarding

Type narrowing is the process of working out from a supertype like
[any](Any.md) or [unknown](Unknown_type_in_TS.md) whic type the value should be in the
x course of your code. This is necessary since a process will not necessarily
always return or involve homogenous types.

Related to this is type guarding: ensuring that a value is of the suitable type
as a factor of control flow. For instance using typeof to ensure that an input
is numerical before proceeding with a function's logic.


title: Single_file_Python_scripts
last_modified: 2024-10-19 09:57:54
body:
# Single file Python scripts

## Basic architecture

```py
#! /usr/local/bin/python3

import sys

if __name__ == "__main__":
    all_args = sys.argv
    specific_arg = sys.argv[0]
    # Main functionality...
```

When you run a script (module) Python assigns the string `__main__` to the
`__name__` attribute to the script that is being executed.

If you run the script as an import into another script, the `__name__` attribute
of the imported module is set to the module name, not `__main__`.

Everything can go under the `__main__` conditional, or, for better readability,
you can define a `main` function that is then invoked, e.g:

```py

def main():
    # Do some stuff


if __name__ == "__main__":
    main()

```

## Related notes

![Python modules and imports](./Python_modules_and_imports.md)


title: 747589ad_effects_of_privacy_violation
last_modified: 2025-01-09 19:03:41
body:
# 747589ad_effects_of_privacy_violation

_What surveillance really is, at its root, is a highly effective form of social
control. The knowledge of always being watched changes our behavior and stifles
dissent. The inability to associate secretly means there is no longer any
possibility for free association. The inability to whisper means there is no
longer any speech that is truly free of coercion, real or implied. Most
profoundly, pervasive surveillance threatens to eliminate the most vital element
of both democracy and social movements: the mental space for people to form
dissenting and unpopular views._

- https://riseup.net/en/about-us/newsletter/2013/08#riseup-and-the-recent-email-provider-closures

_If you live in a surveillance state for long enough, you create a censor in
your head. When video cameras are routine fixtures in urban landscapes; when
corporate Internet giants store records of online navigation and communication;
and when managers and bosses maintain capabilities to measure and monitor
employees as never before, society at large pays the price. These different
vectors of surveillance aggregate, exerting a pressure for us to blend in, to
think twice before speaking out, to, in essence, follow a narrow set of
prescribed norms. Social conformity encourages quiet resignation and discourages
the experimental - and necessarily risky - acts of speaking, thinking, and doing
required for healthy democratic dissent._

Gabriella Coleman. _Hacker, Hoaxer, Whistleblower, Spy_ (2014): 380


title: Processes
last_modified: 2024-10-18 18:55:56
body:
# Processes

Programs are sequences of machine instructions stored in a file. However they do
not work by themselves. Something needs to load the file's intructions into
memory, direct the CPU to run the program and manage it during runtime. The OS
does this via processes.

A process **is a running instance of a given program**. It can be thought of as
a container in which a program runs. This container includes:

- a copy of the program code loaded into memory
- a memory address
- other information about the state of the process

Other than the `init` process started by the kernel (PID1) (see
![systemd](systemd.md)), every process has a parent process that started it.
This parent-child relationship creates a tree of processes.

It is possible that a parent process will terminate before one of its child
processes. In this instance the child becomes an orphan. When this occurs in
#Linux, the orphan process is adopted by `init`.

Below, I have used the `pstree` utility to list all the running processes on my
machine hierarchically.

![diagram of `pstree` output](../img/ps-tree.png)

Children are represented vertically and horizontally.

```
├─terminator─┬─zsh───tmux: client
│            ├─zsh───pstree
│            └─6*[{terminator}]

```

For instance here, `terminator` is a child of `init`, as are `zsh` and `tmux`
but they are also children of `terminator`.`pstree` is a child of `zsh` and
therefore also a child (grandchild) of `terminator`.

Each process has a unique identifier called a _process identifier_, a
_processID_ or just _PID_.

## Related notes

![systemd](./systemd.md)

![ps](./ps.md)

![Monitoring processes and resources](Monitoring_processes_and_resources.md)


title: Memory_leaks
last_modified: 2024-10-18 18:55:56
body:
# Memory leaks

A memory leak occurs when you program memory and forget to delete it once you
are finished. The consequences of memory leak is that it reduces the performance
of the computer by reducing the amount of available memory. Eventually, in the
worst case, too much of the available memory may become allocated and all or
part of the system or device stops working correctly, the application fails, or
the system slows down vastly.


title: Delete_a_branch
last_modified: 2024-10-18 18:55:56
body:
# Delete a branch

### Locally

```bash
git branch -d <local_branch_name>
```

### Remote

```bash
git push origin --delete <remote_branch_name>
```


title: Views_in_relational_databases
last_modified: 2024-10-18 18:55:56
body:
# Views in relational databases

A view is a virtual table that is based on the result-set of a query. Although
it doesn't actually exist in the same manner as an actual table it has exactly
the same properties and functionality. Rather than adding the raw data manually,
you derive it from logic applied to existing actual tables.

This is a good way of dynamically generating data and is often employed as a way
of creating mutations without changing the underlying data structure. In SQL,
views can be created by combining `PRIMARY` and `FOREIGN` keys.


title: AWS_SQS_SDK
last_modified: 2024-11-25 06:50:09
body:
# AWS SQS SDK

## Initialising the SQS client

```ts
import { SQSClient } from "@aws-sdk/client-sqs";

const sqs = new SQSClient({ region: "us-east-1" });
```

## Sending a message to the queue

```ts
import { SendMessageCommand } from "@aws-sdk/client-sqs";

const command = new SendMessageCommand({
  QueueUrl: queueUrl,
  MessageBody: messageBody,
  // Optional parameters
  DelaySeconds: 0,
  MessageAttributes: {
    CustomAttribute: {
      DataType: "String",
      StringValue: "CustomValue",
    },
  },
});

return await sqs.send(command);
```

## Processing messages on the queue

```ts
import { ReceiveMessageCommand } from "@aws-sdk/client-sqs";

const command = new ReceiveMessageCommand({
  QueueUrl: queueUrl,
  MaxNumberOfMessages: 10,
  WaitTimeSeconds: 20, // Long polling
  VisibilityTimeout: 30, // Time other consumers won't see this message
});

const response = await sqs.send(command);

// Then do something

for (const message of response.Messages || []) {
  console.log(message);
}
```

## Removing message from queue

```ts
import { DeleteMessageCommand } from "@aws-sdk/client-sqs";

for (const message of response.Messages || []) {
  await sqs.send(
    new DeleteMessageCommand({
      QueueUrl: queueUrl,
      ReceiptHandle: message.ReceiptHandle,
    }),
  );
}
```

## Query a DLQ

```ts
const checkDLQ = async (dlqUrl: string) => {
  const command = new GetQueueAttributesCommand({
    QueueUrl: dlqUrl,
    AttributeNames: ["ApproximateNumberOfMessages"],
  });

  const response = await sqs.send(command);
  return response.Attributes?.ApproximateNumberOfMessages;
};
```


title: Docker_containers
last_modified: 2024-10-18 18:55:56
body:
# Docker containers

## Launch a container

We launch a container by running, e.g

```sh
docker run hello-world
```

Docker looks for the `hello-world` image in order to start the container. If it
cannot find it, it will fetch the image from DockerHub.

(`docker run` assumes you are saying "run image in container" but you can
specify other Docker objects such as networks.)

The `docker run` command is actually a composite of the following two commands:

```sh
docker create --name [my_container_name] hello-world
docker start [my_container]
```

Here is an applied example:

```
docker run --name my-container debian /bin/echo "Hello, world"
```

This creates and runs a container from the Debian image and executes `/bin/echo`
inside of it. Once you have run the above line, if the process is successful it
will exit. The container will stop running but it will remain in memory. Nothing
will be output (no "Hello, world"), because when you run it, you are _outside_
of the container.

## Launch a container as a daemon

You can also run a container as a [daemon](). In this mode, the container will
run in the background and detach from the console. For example:

```sh
docker run -d debian /bin/sh -c /bin/sh -c "while true; do echo 'Hello!'; sleep 1; done"
```

Inside the container, this will echo "Hello!" every second in an infinite loop
whilst the daemon is active.

The above command will not actually output anything. Instead it wil ouput the
container ID, e.g:

```
2749d796cbd64e9cf57307329e792587c39d8244f2377e62d78f3f3f77eecdb4
```

You can use this to access the log for the container. When you do so, you will
then see the output:

```sh
docker log 2749
hello
hello
hello
...
```

(We could also use the container name to reference the container, if we launched
it with the `--name` param.)

## Stopping a container

```
docker stop 2749
```

There will be a delay because it shuts down gracefully. It sends a SIGINT to the
process in the container with PID 1 (i.e the root or parent process for the
container).

`stop` will keep the container in memory. This means you can still refer bak to
the logs and that it can be restarted.

Instead of `stop`, if you were to use:

```
docker rm 2749
```

The container will be stopped and deleted. The logs are deleted and the
container cannot be recovered.

We can also tell Docker to immediately remove a container after it exits:

```
docker run --rm [image]
```

## Interacting with containers

In the examples so far the container is a closed box. You don't have a terminal
through which you can interact with the container as you would with an OS. You
can only start the container and view its activities by accessing the logs.

For images that have an OS we can use `-i -t` to launch a terminal in
interactive mode.

```sh
docker run -i -t debian /bin/bash
root@0022da12f2f2:/# ls
bin  boot  dev	etc  home  lib	media  mnt  opt  proc  root  run  sbin	srv  sys  tmp  usr  var
root@0022da12f2f2:/# whoami
root
root@0022da12f2f2:/# ls usr/
bin  games  include  lib  libexec  local  sbin	share  src
```

Note that it defaults to the root user.

Containers are lightweight and should only contain the minium environment needed
to run an application. For this reason OSs that are included in an image are
often very stripped-back and many programs and processes will not be there by
default. (Although you could install a package manager and install the commands
you need.)

The previous command launches the container and enters into it with a terminal.
If a container is already running, you can enter into it in terminal mode with
`exec`:

```
docker exec -i -t my_container bash
```

If a container is running in detached mode we can attach to the main process
with `docker attach`

```
docker attach my_container
```

## Container lifecycle

![](/img/container-lifecycle.png)

All containers have a lifecycle represented by five distinct states. Each state
has an associated command:

- created
  - `docker create`, `docker run`
- running
- paused
  - `docker pause`, `docker unpause`
- stopped
  - `docker stop`, `docker kill`
- removed
  - `docker rm`

## Main container commands

```sh
docker create # create container from image
docker run # create and start container from image
docker run --name # add custom name for container
docker ps # list currently active containers
docker ps -a # list all containers (inactive and active)
docker logs # display a container log
docker stop # stop a running container
docker start # starts a stopped (exited) container
docker rm # remove a stopped (exited) container
```

## Container troubleshooting

Lots of diagnostic output:

```
docker inspect container_name
```

List processes (from outside):

```
docker top container_name
```

View logs

```
docker logs container_name
```


title: Data_types_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Data types in Bash

> There is no typing in Bash

- Bash variables do not have types thus bash is neither loosely or strictly
  typed. Anything you apply the identity operator against becomes a character
  string variable.
- Bash is however able to distinguish numerical strings which is why arithmetic
  operations and comparisons work.
- Consequently there is no `null` type either. The closest thing is an empty
  string, i.e. `APPROX_NULL=""` .

## Declarations

You can achieve a sort of typing through the `declare` keyword, although bear in
mind this is not enforced and you do not have to use it.

### `-r` : readonly

```bash
declare -r var1="I'm read only"
```

Roughly equivalent to a `const` : if you attempt to change the value of `var1`
it will fail with an error message.

### `i` : integer

```bash
declare -i var2="43"
```

The script will treat all subsequent occurrences of `var2` as an integer

### `a` : array

```bash
declare -a anArray
```


title: Functions_in_Bash
last_modified: 2024-11-17 15:07:41
body:
# Functions in Bash

We don't name function parameters in the function declaration. Instead we have
an implied index of arguments: `$1, $2, $3,...`. When the function is called,
the first value after the function name becomes `$1` by default, then the
subsequent arguments.

```bash
function expandRange() {
    declare -a expandedRange=()
    for (( i=$1; i<=$2; i++ )); do
        expandedRange+=($i)
    done
    echo "${expandedRange[@]}"
}
```

```bash
expandedRange=$(expandRange 1 4)
echo $expandedRange
# 1 2 3 4
```

## Get all arguments as an array

We can access all the arguments passed to a function using the `$@` syntax we
encountered before when
[passing arguments to scripts](Passing_arguments_to_Bash_scripts.md). (Here a
function is a kind of script in miniature so the process is the same.)

```sh
function numberThings() {
  i=1
  for f in "$@"; do
    echo $i: "$f"
    (( i++ ))
  done
}
```

## Local variables

```bash
var1="I'm variable 1"

function myfunction() {
  var2="I'm variable 2"
  local var3="I'm variable 3"
}

myfunction
echo $var1
echo $var2
echo $var3

# I'm variable 1
# I'm variable 2
```

> The convention is to put functions at the top of the script, after the shebang
> and after the global variables


title: Memory_Management_Unit
last_modified: 2024-10-18 18:55:56
body:
# Memory Management Unit (MMU)

The MMU is the bridge between the physical memory devices of the machine and the
virtual memory space. It is a chip that sits between the CPU and the RAM and
determines the physical location of the memory requested by the kernel as
virtual memory.

![Virtual memory diagram](/img/virtual-memory-diagram.jpg)

## Pages

We use the term **pages** to denote blocks of virtual memory and to distinguish
them from **addresses** as physical blocks. The MMU possesses a **page table**
which is registry logging which pages correspond to which physical blocks.

## Shared pages

Virtual memory allows the sharing of files and memory by multiple processes.
Crucially the shared data doesn't have to be within the address of each process,
instead there is a reference in the page table that each process has access to
the shared data.

## Page faults

There are two kinds of error that can occur with relation to paged memory:

- minor page faults
  - The desired page is in main memory but the MMU doesn't currently know where
    it is
- major page faults
  - The desired page is not in main memory at all. Therefore the kernel must
    fetch it from disk

Minor page faults are very common and are to be expected; they resolve quickly.
On the other hand too many major page faults can slow the system down both
because of the time-costly process of fetching data from disk and because it
demands more kernel resources to locate the missing page, which puts other
processes on hold.


title: Database_options_on_AWS
last_modified: 2024-10-18 18:55:56
body:
# Database options

Amazon offers numerous database options however they are often named differently
or are Amazon's own implementation of a certain database type:

- **Relational databases**

  - Amazon offers two core RDSs: **Amazon Aurora** and **Amazon RDS**. Both
    allow you to use MySQL and PostgreSQL as the management implementation. The
    differences come down to which management implmentations are supported,
    number of backups and throughput. For instance Aurora has higher
    performance, more logging and fail-safes.

- **NoSQL**
  - Document-based databases
    - The obvious candidate for this kind of database is MongoDB. Amazon doesn't
      offer MongoDB it offers its own implementation which is almost identical
      and compatible with Mongo: **Amazon DocumentDB**. (There is some bitching
      about this from Mongo but they are competitors.)
  - Key-value database
    - A key-value database is basically a hash-table or a map
    - The Amazon implementation of this is **DynamoDB**
    - Confusingly, for NoSQL, a DynamoDB instance comprises "tables" which are
      groupings of keys and values. I guess "table" here is meant in terms of
      "hash table"
    - A cool feature is that you can subscribe to a DynamoDB table and run a
      lambda when a value changes.


title: Formal_proofs_in_propositional_logic
last_modified: 2024-10-18 18:55:56
body:
# Formal proofs in propositional logic

When we construct a formal proof in logic we are seeking to show that a certain
proposition is **derivable** from other propositions. We use the words
_derivation_ and _proof_ interchangeably.

> A sentence $P$ is derivable in a system of propositional logic from a finite
> set of sentences if and only if there is a derivation in this system in which
> all and only the members of the set are **primary assumptions** and $P$ is the
> sentence on the last line.

We express the above symbolically as $\Gamma \vdash P$ . (Be careful not to
confuse _derivable_ ($\vdash$) from _entails_ ($\vDash$).

Derivability is therefore a property that a proposition can possess relative to
a set.

For instance to demonstrate derivability for:

$$
\{ \lnot F \lor D, F, D \rightarrow (G \land H) \} \vdash G \land H
$$

We would establish $\lnot F \lor D, F, D \rightarrow (G \land H)$ as primary
assumptions and then, using the derivation rules of the system conclude with
$G\land H$. Every sentence in the derivation is either a **primary assumption**
or an **auxiliary** assumption or justified by the rules of the derivation.

An auxiliary assumption is an assumption belonging to a sub-derivation. Primary
assumptions belong to the main derivation. For any given derivation of the form
$\Gamma \vdash P$ there may be a number of ways of demonstrating the derivation
(more than one application of the rules governing the system) but one alone is
sufficient to establish derivability.

> We will tend to use the terms _derivation_ and _proof_ interchangeably but we
> should note that there is a technical distinction in that a **proof is a
> derivation in which all of the assumptions have been discharged**

## Constructing proofs

We place assumptions above derivations and mark them _A_ in the right-hand
margin. We use a shorthand for the derivation rules and also place these in the
right-hand margin.

We divide assumptions from derivations with a horizontal line. We number each
line and use this to refer to the line we are applying the derivation to.
Sub-proofs follow this structure recursively. This is known as _Fitch notation_

_Schematically_:

![](/img/proofs-drawio-Page-5.drawio.png)

_Applied example_:

![](/img/proofs-drawio-Page-6.drawio.png)

## Sub-proofs

When a sub-proof is terminated, the assumption with which it starts is said to
be _discharged_. It's conclusion can then be drawn upon and invoked within the
main proof by reference to its start and end line number. However statements
within the sub-proof cannot be referred to again from within the main proof,
only its result.

## Derivation rules

Derivation rules are
[syntactic](Syntax_of_sentential_logic.md) rather
than semantic. They are applied on the basis of their form rather than on the
basis of the truth conditions of the sentences they are applied to.

> Derivation rules can be applied without having an interpretation of the
> symbols in mind. A derivation rule tells us that: given a group of symbols
> with a certain structure, we can write down another group of symbols with a
> certain structure.

Each of the main logical connectives has an associated derivation rule. The
binary connectives have pairs of rules, one for the introduction of the
connective and one for its elimination.

The main derivation rules:

- [Negation Introduction](Negation_Introduction.md)
- [Negation Elimination](Negation_Elimination.md)
- [Conjunction Introduction](Conjunction_Introduction.md)
- [Conjunction Elimination](Conditional_Elimination.md)
- [Disjunction Introduction](Disjunction_Introduction.md)
- [Disjunction Elimination](Disjunction_Elimination.md)
- [Conditional Introduction](Conditional_Introduction.md)
- [Disjunction Elimination](Disjunction_Elimination.md)
- [Biconditional Introduction](Biconditional_Introduction.md)
- [Biconditional Elimination](Biconditional_Elimination.md)


title: Law_of_Non_Contradiction
last_modified: 2024-10-18 18:55:56
body:
# Law of Non-Contradiction

> A proposition cannot be true and false at the same time.

$$
\lnot (P \land  \lnot P)
$$


title: Lifecycle_methods
last_modified: 2024-10-18 18:55:56
body:
# Lifecycle methods

Lifecycles are familiar from nature: something is born, it grows and reaches
maturity and then dies and the process continues as what dies is broken down
into constituent parts which form the basis of new life. And so on and so on.

The same metaphor can be applied to React components relative to the document
object model:

- Components are 'born' (created and mounted on the DOM)
- They 'grow' by changing and updating their state
- They 'die' by being unmounted from the DOM

## Specific lifecycle phases

The outline above corresponds to specific methods that execute when React code
runs:

1. `componentWillMount()` : this method is called just before the `render()`
   method is called
2. `componentDidMount()` : this method is called after the component is rendered
   in the DOM

The two methods above only occur once in a lifecycle.

The 'updating' phase is achieved with the following methods. This is when the
data of the component, in the form of state and props updates in response to
user interaction. We call this process 're-rendering':

3. `shouldComponentUpdate()` : determines whether component should update

4. `componentWillUpdate()` : called before re-rerendering occurs

5. `componentDidUpdate()` : called after re-rendering occurs

The final phase is unmounting: when the component is removed from the DOM:

6. `componentWillUnmount()`

![React component lifecycle](react-lifecycle.png)

## Side-effects: why lifecycle phases matter

> React is built based on the principles of functional programming. In this
> paradigm, a side-effect (something that is generally discouraged) is any
> process that is not the direct result of a function executing or anything that
> is not covered by the `return` keyword.

Many of the methods detailed in the previous section will rarely be used in
React development since they pertain to the inner engineering of the library,
rather than its application in custom contexts. However sometimes you do need
access to these methods, depending on the background context of what you are
trying to achieving. This context could include external API and database
requests or **anything that does not directly pertain to the rendering of the
component on the screen**.

React groups these processes under the heading of **side-effects.**

### Examples of side-effects and where in the lifecycle they should run

- `componentWillMount` : It's a good idea to run set-up scripts at this point,
  such as connecting to and authenticating access to a database. This process
  runs before the `render` method is called so it is an optimal point to
  establish these connections
  - You should not however make data requests at this point since data is
    typically returned asynchronously. You cannot therefore be sure that the
    data will be returned before mounting occurs.
- `componentDidMount` : This is the time to do things that can't occur without
  the DOM:
  - retrieve data
  - add event listeners
  - set timers using `setTimeout` or `setInterval`
- Updating methods (`shouldComponentUpdate`, `componentWillUpdate` etc.)
  - As these precede or take place concurrently with the rerendering process,
    this phase is a good point to retrieve new data or run necessary external
    processes that are required by the re-rendering.


title: bbdcb54f_public_key_cryptography
last_modified: 2024-12-20 13:12:22
body:
# bbdcb54f_public_key_cryptography

_A_ wants to send a message to _B_. A wants to ensure that only _B_ can read the
message and that it is not intercepted or altered during transmission to _B_.

Think of _B_ as being in possession of a letterbox. The letterbox contains
messages that only he can read. Anyone can put letters in it for _B_ to read but
_B_ alone can read them.

This is achieved by encyrpting the messages with two keys: a public key and a
private key. The public key can be shared with others and anyone in possession
of the public key can encrypt a message for _B_. Once encrypted, only _B_ can
decrypt it using his private key. Once receiving the message, B uses his private
secret key - that he doesn't share with anyone else - to decrypt. This is the
equivalent to opening up the letterbox and taking out the letters.

Another useful analogy is to think of invisible ink. Anyone can write a letter
using the invisible ink but only the recipient has the liquid that can render it
visible again. Anyone intercepting the message (without the liquid) will see
nothing, equivalent to the encrypted data.

This is asymmetric encryption because the two communicating parties do not have
equal access to the messages exchanged. _A_ can only send messages - he can't
decrypt them, only _B_ can. So _A_ is unequal relative to _B_. With symmetric
encryption _A_ and _B_ would both share a single private key which they would
each use to encrypt and decrypt their messages.


title: systemd
last_modified: 2024-10-18 18:55:56
body:
# systemd

Once the [boot process](Boot_process.md) has completed and the bootloader has
located the kernel and injected it into memory the first user space program
runs: `init` (for _initialisation_). `init` is a [daemon](Daemons.md)
[process](./Processes.md) that continues running until shutdown and is
responsible for starting all the processes that are prerequisites for user
space. For example: network connections, disk access, user logins etc. `init` is
the parent of all processes: PID1. Whilst it does a lot of its work in quick
succession at boot time it is not limited to the this stage of the lifescycle
but runs continuously in reponse to new user events.

On Linux systems `systemd` is used to implement `init` and therefore `systemd`
will always be listed as PID1.

`systemd` is directly accessible from user space and provides a straightforward
way to enable/disable, start/stop system level processes

> `systemd` can track individual service daemons after they start, and group
> together multiple processes associated with a service, giving you more power
> and insight into exactly what is running on the system _How Linux Works: Third
> Edition_, Brian Ward 2021

## How systemd works

### Goal-directed units

`systemd` works on the basis of _goals_. Each goal is system task defined as a
**unit**. A unit contains instructions and a specification of dependencies to
other units.

When activating a unit, `systemd` first activates the dependencies and then
moves onto the details of the unit itself. `init` as implemented by `systemd`
does not follow a rigid sequence every time, initialising units in the same
sequence and waiting for one to complete before starting another. Instead it
activates units whenever they are ready. This, its parallelized nature, is one
of the main advantages over previous programs that managed the `init` sequence
on Linux (such as for example System V);

### Unit types

Units are organised into **unit types**. The main types that run at boot time
are as follows:

- service units (`.service`)
  - control service daemons
- socket units (`.socket`)
  - handle incoming network connection request locations
- device units (`.device`)
  - disks and other devices
- mount units (`.mount`)
  - handle the attachment of filesystems to the system
- target units
  - control other units by organising them into groups

For example, at boot, a target unit called `default.target` groups together a
number of service and mount units as dependencies. These then run in a
graph-like dependency structure where a unit that comes late in the boot process
can depend on several previous units making earlier branches of a dependency
tree join back together.

## systemd configuration files

Units are managed via `systemd` configuration files.

### Configuration file locations

System level `systemd` config files are located in the _system unit directory_
at `/usr/lib/systemd/system`. You shouldn't change or manipulate these files or
attempt to add new config files here since they will be overwritten by the
system.

![](/img/systemd-global-files.png) _`systemd` global unit files_

Local definitions that relate to the specific user and where the user herself
can define units are located in the _system configuration_ directory:
`/etc/systemd/system`.

![](/img/systemd-local-files.png)

_`systemd` local unit files, specific to the currently logged-in user_

### Example files

Below is the systemd service file for the creation of UUIDs:

```plain
[Unit]
Description=Daemon for generating UUIDs
Documentation=man:uuidd(8)
Requires=uuidd.socket

[Service]
ExecStart=/usr/sbin/uuidd --socket-activation
Restart=no
User=uuidd
Group=uuidd
ProtectSystem=strict
ProtectHome=yes
PrivateDevices=yes
PrivateUsers=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
MemoryDenyWriteExecute=yes
ReadWritePaths=/var/lib/libuuid/
SystemCallFilter=@default @file-system @basic-io @system-service @signal @io-event @network-io

[Install]
Also=uuidd.socket
```

- The `Unit` section provides metadata about the unit including which `systemd`
  dependencies it has
- `Service` constitutes the main specification for the unit
- `Install` is the call to set the dependencies running before the `Service`
  functions are accessible.

## systemd operations: systemctl

The `systemctl` command is the chief way of interacting with `systemd`. You use
it to activate and deactivate services, list their status, reload the
configuration and so.

### View the dependency graph

`systemctl status` by itself will print a long list of units grouped by their
dependency relations. It will also provide some metadata about the current
systemd boot context.

### Viewing active units

Below I have listed the running units pertaining to bluetooth:

```
$ systemctl list-units | grep bluetooth
 sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0-hci0:3585.device                                   loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0/hci0:3585
  sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0.device                                             loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0
  sys-subsystem-bluetooth-devices-hci0.device                                                                                    loaded active plugged   /sys/subsystem/bluetooth/devices/hci0
  sys-subsystem-bluetooth-devices-hci0:3585.device                                                                               loaded active plugged   /sys/subsystem/bluetooth/devices/hci0:3585
  bluetooth.service                                                                                                              loaded active running   Bluetooth service
  bluetooth.target                                                                                                               loaded active active    Bluetooth Support
```

### List jobs

Requests to activate, reactivate and restart units are called **jobs** in
`systemd`. They can be thought of as unit state changes. Current jobs can be
listed with `systemctl list-jobs`.

This will most likely return `No jobs running` if the computer has been running
for a while. Most jobs execute at boot.

### Enable/disable, start/stop units

If a unit has dependencies it is necessary to _enable_ it before starting it.
This installs the dependencies.

```bash
systemctl enable mongodb.service
Created symlink /etc/systemd/system/multi-user.target.wants/mongodb.service → /usr/lib/systemd/system/mongodb.service.
```

Then we can start:

```
systemctl start mongodb.service
```

To stop the service:

```
systemctl stop mongodb.service
```

After this we should disable it, in order to remove any symbolic links it has
created on the system as part of the install process:

```bash
systemctl disable mongodb.service
Removed "/etc/systemd/system/multi-user.target.wants/mongodb.service".
```

## Why use systemd over cron ?

https://mark.stosberg.com/2016-08-26-rsnapshot-and-systemd/


title: Solving_equations
last_modified: 2024-10-19 09:58:04
body:
# Solving equations

## Use inversion of operators

When solving equations we frequently make use of the
[ operator inversion rules](Inversion%20of%20operators.md) to find the
solutions.

### Example: inversion of addition

For example, the equation $9 = 3 + x$ has the solution $6$ ($x$ is equal to
$6$). To arrive at this, we can use the inverse of the main operator in the
equation (addition): $9-3 = 6$.

### Example: inversion of subtraction

Now consider $19 = x - 3$. The solution to this equation is $22$ ($x$ is equal
to $22$). To arrive at this, we can use the inverse of the main operator in the
equation (subtraction): $19 + 3 = 22$.

### Example: inversion of division

The equation we want to solve: $$\frac{x}{6} = 4$$

Now we invert it by multiplying the denominator by the quotient:
$6\cdot 4 = 24$. Therefore: $$ \frac{24}{6} = 4$$
The solution is $24$

### Example: inversion of multiplication

The equation we want to solve: $$4x = 36$$ Now we invert it by dividing the
product by the coefficient: !Add link to 'coefficient'

$$\frac{36}{4} = 9$$

Therefore the solution is $9$: $$ 4(9) = 36$$


title: Iterating_in_React
last_modified: 2024-10-18 18:55:56
body:
# Iterating through data

As React follows the **functional programming paradigm** and state versioning,
looping is not the recommended way of engineering repeated processes since it
presupposes pre-existing state. Instead React relies on the functional methods
of modern JavaScript such as `map` , `filter` , `reduce` to output the values of
iterative data structures.

Instead of mutating the state of a reference type, these methods are
'non-destructive': they create a new array that meets the requirements set in
the particular method. These newly created arrays and objects therefore form the
basis of the state versioning, because each new array that is engendered, is a
new state configuration.

## The `key` attribute

The `key` attribute is a special React attribute that should be added to the
elements of any listed content (i.e numbered lists, unordered lists, `select`
options etc; basically anything rendered that comes about through mapping arrays
and objects).

This enables React to monitor the state of the list: which items have changed,
been added, or removed.

The best way to pick a key is to use a string that uniquely identifies a list
item among its siblings.

For instance, using our earlier `numbers` array, assuming each number is unique,
we could use the number itself as the key:

```jsx
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => (
  <li key={number.toString()}> {number}</li>
));
```

> Keys have to be unique to the individual element and not shared by any other
> sibling. But they do not need to be globally unique. You could use the same
> `key` name in another array list.

> Keys should be string types, not other data types. You can use the
> `.toString()` method to ensure this is the case.

If you can't find a unique basis for naming a series of keys, you can use the
`index` value of the `Array.map` function. This should only be used if the order
of the items doesn't change. An example:

```jsx
class List extends React.Component {
  render() {
    const demoArr = ["cat", "dog", "mouse"];
    return (
        <ul>
          {demoArr.map((x, index) => (
            <li key={index}>{x}</li>
          ))}
        </ul>
      </div>
    );
  }
}
```

## Demonstration

### Source data

```jsx
const blogData = [
  {
    id: 1,
    date: "2020-11-15",
        shortByline:
      "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
    longByline:
      "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
    image: blogImage,
  },
  {
    id: 2,
    date: "2020-08-11",
        shortByline:
      "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
    longByline:
      "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
    image: blogImage,
  },
];
```

### Child component

```jsx
export default function BlogPreviewCard(props) {
  return (
    <Card>
      <CardMedia image={props.image} />
      <CardContent>
        <Typography>{props.date}</Typography>
        <Typography>{props.title}</Typography>
        <Typography>{props.shortByline}</Typography>
      </CardContent>
      <CardActions>
        <Button>Read</Button>
      </CardActions>
    </Card>
  );
}
```

### Iteration

```jsx
// This uses the Material-UI grid component

import BlogPreviewCard from "../components/BlogPreviewCard"
import blogData from "../data/blogData

export default function BlogPreviewSet() {
  return (
    <Grid>
      {blogDummyData.map((data, index) => (
        <Grid key={index}>
          <BlogPreviewCard key={index} {...data} />
        </Grid>
      ))}
    </Grid>
  )
}
```


title: SAM
last_modified: 2024-10-18 18:55:56
body:
# AWS SAM

SAM stands for **serverless application model**. It is a framework developed by
AWS to simplify the process of building, deploying and managing serverless
applications. It provides a concise syntax for defining the components of a
serverless application, such as
[Lambda functions](zk/Lambda_programming_model.md),
[API gateway](/zk/AWS_API_Gateway.md) and database tables.

The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
SAM syntax gets transformed into CloudFormation during the deployment process.
(CloudFormation is a broader and more robust AWS tool for large, highly
scaleable infrastructures).

## Key features of SAM

- Single deployment configuration
- Integration with development tools
- Local testing and debugging
- Built on AWS CloudFormation

## Main technologies required

### Docker

Whilst SAM can be used to create a deployable file for AWS it can also be run as
a container for local development with Docker.

### AWS CLI

This is installed using Python and allows you to interact directly with AWS via
the command-line.

### AWS SAM CLI

See
[https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)

## Setting up credentials for the AWS CLI

You require an access key for the given
[IAM user](zk/AWS_User_management_and_roles.md#iam). You should create an IAM
account specific to the project with bounded permissions.

```
aws configure
AWS Access Key ID [None]: AK*******
AWS Secret Access Key [None]: ukp******
Default region name [None]:
Default output format [None]:
```

This information can be found in the Security Credentials section of the given
[IAM](zk/AWS_User_management_and_roles.md#iam) user:

![](/img/access-key-aws.png)

### Switching between credentials

You should set up a different IAM user for each project.

You can do this with:

```sh
aws configure --profile <profile-name>
```

This will then ask you to add the credentials for the user.

You can switch between different credentials for the user as follows:

```sh
AWS_PROFILE=<profile-name> sam build

```

## Starting a SAM project

First create a directory for your project which will serve as the repository:

```sh
mkdir aws-sam-learning
cd aws-sam-learning
```

Then we can use the `sam` cli to bootstrap the project:

```sh
sam init --runtime nodejs16.x
```

We can just click through and accept the basic HelloWorld Lambda.

This will create the Lambda as well as an API Gateway trigger URL.

### `template.yaml`

This is autogenerated and details the main constituents of the project. There
are lots of fields but the most important are the following:

```yaml
HelloWorldFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: hello-world/
    Handler: app.lambdaHandler
    Runtime: nodejs16.x
    Architectures:
      - x86_64
    Events:
      HelloWorld:
        Type: Api
        Properties:
          Path: /hello
          Method: get
```

This details the location of the [handler function](/Lambda_handler_function.md)
which is contained at the path `hello-world/app.js`:

```js
exports.lambdaHandler = async (event, context) => {
  try {
    // const ret = await axios(url);
    response = {
      statusCode: 200,
      body: JSON.stringify({
        message: "hello world",
        // location: ret.data.trim()
      }),
    };
  } catch (err) {
    console.log(err);
    return err;
  }

  return response;
};
```

It also lists the `get` event that we can use to call API Gateway and trigger
the Lambda.

The full template is below:

![](/img/sam-template-yaml.png)

## Adding our own code

We will create our own function and API Gateway trigger.

We will place our function after the existing `HelloWorldFunction`

```yaml
ClockFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: clock/
    Handler: handler.clock
    Runtime: nodejs16.x
  Events:
    ClockApi:
      Type: Api
      Properties:
        Path: /clock
        Method: get
```

We can test the syntax with:

```sh
sam validate
```

Just like with `HelloWorld`, we will create a directory for this function:
`clock` and we will initialise it as an `npm` project.

```sh
mkdir clock
cd clock
npm init
```

We will use `handler.js` as our root, handler function.

We have said in the template file that our `Handler: handler.clock`, therefore
the main function in the `handler` module should be `clock`:

```js
const moment = require("moment");

exports.clock = async (event) => {
  console.log("Clock function run");
  const message = moment().format();
  const response = {
    statusCode: 200,
    body: JSON.stringify(message),
  };
  return response;
};
```

The directory structure is as follows:

![](/_img/sam-directory.png)

When we call the API Gateway path `/clock` with `GET`, our function will be
triggered.

## Deploying the project

We will now deploy our project to AWS from the local environment.

The process is as follows:

1. Build
2. Package
3. Deploy

### Build

We need to install the runtime dependencies for the function. We do this by
running `sam build`. This ignores test files and development dependencies and
installs the project dependencies and source files to a temporary subdirectory.

![](/img/sam-build.png)

The build directory is `.aws-sam/build/`. There will be a subdirectory for each
of our files.

### Package

As noted, CloudFront handles the deployment of the application. It can only
receive one file as an input. The packaging process consists in creating that
single file.

The packaging proces will first archive all of the project artefacts into a zip
file and then upload that to [S3](zk/AWS_S3.md). A reference to this S3 entity
is then provided to CloudFormation.

![](/img/s3-package-again.svg)

The command is as follows:

```sh
sam package
  --template-file template.yaml
  --output-template-file pkg.yml
  --region eu-west-1
```

This will automatically create a hashed bucket name for you in S3 (I have tried
to add my own naming but it doesn't comply.)

### Local development with Docker

In order to work with your application locally without actually sending requests
to AWS and using credit, you can run a local instance.

See [Local AWS Development with SAM](zk/Local_AWS_development_with_SAM.md).

### Deploy

Once you have packaged the app you can deploy with `sam deploy --guided`. This
will talk you through the defaults and will deploy the package to
CloudFormation. In CloudFormation each individual project is called a **stack**.

If we then go to Cloud Formation we will see the deployed application.

![](/img/cloud-formation-stack.png)

## Call the endpoint

If we now go to the Lambda console, we will see our function listed, and the API
Gateway endpoint under `triggers`:

![](/img/gateway-trigger.png)

We can then call this from Postman to check everything is working as it should:

![](/img/postman-aws-output.png)


title: Compile_Python_app_to_single_executable
last_modified: 2024-10-19 12:56:50
body:
# Compile Python app to single executable

Assume you are already using a Pip venv.

Install `pyinstaller` and/or add it to your `requirements.txt`:

```sh
souce venv/bin/activate
pip install pyinstaller
pip install -r requirements.txt
```

Then from root of project:

```sh
pyinstall -F src/app.py
```

The `-F` flag compiles the application to a single file containing all necessary
external packages and local imports.

It outpute to `/dist`. Say the app is called `hello`, run the executable thus:

```sh
/my-python-application/dist/app
```


title: Working_with_numbers_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Working with numbers in Bash

We distinguish:

- **arithmetic expansion** `$(( ))`
  - returns the result of literal numbers that can then be stored in a variable
- **artihmetic evaluation** `(( ))`
  - perform calculations on _existing_ variables

An example of expansion:

```bash
a=3
((a += 3))
echo $a
# 6
((a++))
# 7
```

> Note: we do not use a dollar-sign when referring to variables within
> arithmetic evaluation, there is no need. If we do, we get an error. This is
> because we are using an
> [expansion](Expansions_and_substitutions.md),
> therefore the variables are already being interpreted as variables.

## Declaring variables as integers

It is good practice to safeguard against Bash treating numbers as strings to
declare them as integers in addition to using arithmetic evaluation, e.g:

```bash
declare -i b=3
```

Whilst this isn't a strict type, it means we can do this:

```bash
b=$b+4
echo b
# 7
```

Without getting `3+4` in return

## No decimals in bash

Bash does not support decimal calculations natively. This is what you'd get for
example:

```bash
echo $(( 1/3 ))
# 0 (not 0.33)
```

So work with decimals you should use `awk` or `bc` ("basic calculations").

Example of using `bc`:

```bash
declare -i c=1
declare -i d=3
e=$(echo "scale=3; $c/$d" | bc)
# 0.333
```

## Random numbers

Generate a pseudo-random number between 1 and 20:

```bash
echo $(( 1 + RANDOM % 10))
# 18
```


title: jq
last_modified: 2024-10-18 18:55:56
body:
# jq

## Remove property

Remove property from a JSON array of objects:

```json
{
  "member_inputs": [
    {
      "name": "Thomas",
      "input_type": "select"
    },
    {
      "name": "Martha",
      "input_type": "text"
    }
  ]
}
```

```sh
jq '.member_details |= map(del(.input_type))' memberDetails.json
```

> Add '-i' to modify the source file directly (in-place)

> Multiple properties can be deleted simply by chaining,
> e.g.`(del(.input_type, .another_property))`


title: Testing_basic_prop_passing_in_React
last_modified: 2024-11-04 14:21:35
body:
# Testing basic prop passing in React

```js
import { render, screen } from "@testing-library/react";

describe("<CertificateHtml />", () => {
  it("should render the values passed as props", () => {
    // Arrange:
    const stub = {
      titleOfActivityOrProgramme: "Filming",
      nameOfDepartment: "The film department",
    };

    // Act:
    render(<CertificateHtml {...stub} />);

    // Assert:
    expect(screen.getByText("Filming")).toBeInTheDocument();
    expect(screen.getByText("The film department")).toBeInTheDocument();
  });
});
```

Or, loop:

```js
for (const entry of Object.values(stub)) {
  expect(screen.getByText(entry)).toBeInTheDocument();
}
```


title: Error_handling_in_Python
last_modified: 2024-10-25 09:32:22
body:
# Error handling and exceptions in Python

Errors can typically occur in the following scenarios:

- A file or resource that is referred to does not exist
- A network connection fails
- A module import error occurs

In these scenarios you would want to allow for error handling, so that you can
detect errors and respond appropriately.

## Difference between errors and exceptions.

Python distinguises between errors and exceptions.

- An error typically indicates a situration where something goes wrong before
  the execution of the program begins.
- An exception arises during the execution of the program

In contrast to a error, when an exception occurs, the program doesn't
necessarily stop immediately. Instead, Python provides a way to handle the
exception, allowing you to potentially recover from it, or at least, to handle
it gracefully before the program stops.

However if you do not implement exception handling, the program will stop
immediately when an exception occurs, similar to a error.

## The Exception hierarchy

Errors and Exceptions are objects in Python and there is no real syntactic
distinction between the two since all errors and exceptions in herit from a base
exception class.

The root class is `BaseException` which all errors and exeptions extend as
subclasses as demonstrated by this diagram:

![](/img/python-exception-hierarchy.png)

## Exception syntax

### Difference between `raise` and `except`:

- `raise` is used to explicitly trigger an exception - it means that you are
  signalling that an exception condition _has_ occured in your program.
- `except` is used in conjunction with `try`blocks to catch and handle
  exceptions. Here you are saying "I think this _might_ cause an exception, so
  let's be prepared to handle it".

Exaple of `raise`:

```py
x = -10
if x < 0:
    raise ValueError("The value should not be negative!")
```

Example of `except`:

```py
try:
    result = 10 / 0
except ZeroDivisionError:
    print("You can't divide by zero!")

```

### Scaffolding exception handling

There is a general procedure for handling exceptions denoted by certain
keywords:

- `try`
  - The process you want to run
- `except`
  - The errors that could occur. You can have multiple `except` clauses for
    different exceptions
- `else`
  - Some code you want to run after each of the `except` clauses have run
  - It must be written after the `except` clauses
  - It runs **if and only if** no exceptions were raised
  - If `try` succeeds or an exception is thrown, `else` will not run
- `finally`
  - What you want to run at the end of the `try, except, else` sequence

```py
try
    run_calculation(7)
except ZeroDivisionError:
    print('something')
except IndexError:
    print('something')
except FileNotFoundError:
    print('something')
except Exception:
    print('something')
else
    # Do something after the exception blocks
finally
    # Do concluding action
```

## Custom exceptions

You can create your own custom exceptions by creating a class that inherits from
the `Exception` class.

```py
class CustomError(Exception):
    pass

try:
    raise CustomError("This is a custom exception!")
except CustomError as e:
    print(f"Caught an exception: {e}")
```


title: Syntax_of_propositional_logic
last_modified: 2024-10-18 18:55:56
body:
# Syntax of propositional logic

## Syntax of formal languages versus semantics

> The syntactical study of a language is the study of the expressions of the
> language and the relations among them _without regard_ to the possible
> interpretations or 'meaning' of these expressions.

Syntax is talking about the order and placement of propositions relative to
connectives and what constitutes a well-formed expression in these terms.
Semantics is about what the connectives mean, in other words: truth-functions
and truth-values and not just placement and order.

## Formal specification of the syntax of the language of Sentential Logic

### Vocabulary

Propositions in SL are capitalised Roman letters (non-bold) with or without
natural number subscripts. We may call these proposition letters. For example:

$$
  P, Q, R,... P_{1}, Q_{1}, R_{1}, ...
$$

The connectives of SL are the five truth-functional connectives:

$$
  \lnot, \land, \lor, \rightarrow, \leftrightarrow
$$

The punctuation marks of SL consist in the left and right parentheses:

$$
  ( )
$$

### Grammar

1. Every letter in a statement is a proposition.
2. If $P$ is a proposition then $\lnot P$ is a proposition.
3. If $P$ and $Q$ are propositions, then $P \land Q$ is a proposition
4. If $P$ and $Q$ are propositions, then $P \lor Q$ is a proposition
5. If $P$ and $Q$ are propositions, then $P \rightarrow Q$ is a proposition
6. If $P$ and $Q$ are propositions, then $P \leftrightarrow Q$ is a proposition
7. Nothing is a proposition unless it can be formed by repeated application of
   rules 1-6

### Additional syntactic concepts

We also distinguish:

- the **main connective**
- **immediate sentential components**
- **sentential components**
- **atomic components**

These definitions provide a formal specification of the concepts of
[atomic and molecular propositions](Atomic_and_molecular_propositions.md)
introduced previously.

1. If $P$ is an atomic proposition, $P$ contains no connectives and hence does
   not have a main connective. $P$ has no immediate propositional components.
1. If $P$ is of the form $\lnot Q$ where $Q$ is a proposition, then the main
   connective of $P$ is the negation symbol that occurs before $Q$ and $Q$ is
   the immediate propositional component of $P$
1. If P is of the form:
   1. $Q \land R$
   1. $Q \lor R$
   1. $Q \rightarrow R$
   1. $Q \leftrightarrow R$

where $Q$ and $R$ are propositions, then the main connective of $P$ is the
connective that occurs between $Q$ and $R$ and $Q$ and $R$ are the immediate
propositional components of $P$.


title: LEDs
last_modified: 2024-10-18 18:55:56
body:
# LEDs

LED' stands for **Light Emitting Diode**, a [circuit]() component that emits
light. The symbol for an LED is displayed below:

![](/img/diode-led.png)

A **diode** is a special kind of component that only permits current to flow
through it in one direction. To achieve this it has very low resistance in one
direction to allow current flow and high resistance in the other direction to
impede current flow. This feature of diodes is clearly represented in the
generic diode circuit symbol:

![](/img/diode.png)

An LED diode lights up when the right amount of current flows through it. A
standard LED has a maximum current of 20mA. An appropriate
[resistor](Resistance.md#resistors)
must therefore be added to the circuit to ensure the current doesn't exceed this
amount.


title: Transistors
last_modified: 2024-10-18 18:55:56
body:
# Transistors

A digital circuit requires that electrical phenomena be treated as discrete
rather than continuous values.

Although a given voltage at a point in the circuit can vary widely, in order to
represent the binary states of 'on' and 'off' we need it to remain fixed within
certain narrow parameters. This is achieved with transistors.

Transistors are an electrical component that is capable of controlling the flow
of current in the manner of a switch where the 'off' and 'on' states are
represented by [voltage](Voltage.md) values within set parameters.

There are different types of transistors but the simplest for the purposes of
explanation are **bipolar junction transistors**.

![BJT transistor terminals](../img/bjt-terminals.jpg)

The pins:

- C: collector
- B: base
- E: emitter

Applying a small amount of current at the base allows a larger current to flow
from the collector to the emitter. Applying current to the base is like turning
the switch on. Removing this current is like turning the switch off.

This happens because of how current and voltage interact in a transistor. The
small base current controls the larger collector-emitter current through a
process called current amplification.

When a small voltage is applied to the base, it allows a small current to flow
from the base to the emitter. This base current triggers a much larger current
to flow from the collector to the emitter. Think of it like a water valve: a
small turn of the handle (base current) can control a large flow of water
(collector-emitter current). The transistor amplifies this effect, allowing a
tiny input signal to control a much larger output.

## Transistors and logic gates

We can combine transistors to create logic gates. A logic gate is a combination
of transistors arranged such that the logical function is embodied by the
characteristic input and output voltages to the transistor.

For example to create an [AND](Logic_gates.md#and-gate) gate we would have two
voltage inputs going into two transistors that are connected in sequence. The
two transistors create a continuous line going from the collector of one to the
emitter of the other. If either voltage input is low then the voltage of the
combined line is low (equivalent to the circuit being broken) and there is no
current flowing.

![](/img/and-transistor.png)

// Add example of OR gate created with transistors


title: React_Components
last_modified: 2024-10-18 18:55:56
body:
# Components

We write functional components in the manner of a normal
[function](Functions.md) that take
a props argument and return a JSX element.

```jsx
interface IProps = {
  message: string;
};
const App = ({message}: IProps): JSX.Element => <div>{message}</div>;
```

## `React.FunctionComponent` / `React.FC`

It used to be the case that you would type a function component like so:

```jsx
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);
```

This is now discouraged as it means the component can always accept children,
even when you do not want this to be the case. There are several other minor
drawerbacks but it's generally best to leave out the declaration.


title: Read_command__in_Bash
last_modified: 2024-10-18 18:55:56
body:
# read

The primary use of `read` is to capture user input from `stdin`. It can also be
used to parse strings or files that are redirected to it (with `<` and `<<`) or
piped to it. In each case, what is read is stored as a variable.

`read` will parse line by line using a space (`\n`) as the default delimiter.
You can use IFS to parse by other characters and/or
[split the contents into an array](Split_into_array_in_Bash.md).

## Example of capturing user input

When we use `read` to gather user input, the script will pause until the input
is provided.

```bash
echo "What is your name?"
read name

echo "What is your password?"
read -s pass

read

```

> If you don't specify variables, `read` will automatically parse using
> whitespace

## Example of piping to read

Here we use [find](Find_Bash_command.md) to collate the files in
the current directory and then pipe them to read.

```bash
find -type -f  -not -path "./.git/" | read $fname
```

## Example of parsing a file

We will typically read from a source and then do something with each variable
that `read` returns, e.g:

```bash
while read line; do
  if [ var == 'something' ]; then
    # do something
done < './input-file.txt
```

## $REPLY

If you do not assign a variable name to store the value that `read` reads a
default (`$REPLY`) is applied. You can reference this value in your code.

For example the following loop does something if `$REPLY` is equal to an empty
string:

```bash
while read;
do
    ((count++))
    if [[ -z "$REPLY" ]]; then
        echo "$count"
    fi
done < "$input
```


title: VirtualMemory
last_modified: 2024-10-19 10:18:48
body:
# Virtual memory

Virtual memory is an abstracted and idealised representation of the physical
memory capacity of a machine that is presented to user space for its memory
operations.

When an OS implements virtual memory, [processes](./Processes.md) in
[user space](./User_Space.md) cannot directly read or write to the physical
memory. Instead they execute memory operations against virtual memory and the
[kernel](./The_kernel.md) translates these into the actual operations against
the memory hardware.

The main benefits:

- User mode processes do not have to be concerned with the physical memory
  management
- There is a buffer between user mode processes and physical memory, meaning
  that memory cannot be accidentally corrupted by other processes in user space.

Because the physical memory is abstracted, it can be the case that the physical
[memory addresses](./Memory_addresses.md) are non-contiguous or even distributed
accross different hardware components (such as the
[cache](./Register_and_cache_memory.md) and [swap](./Swap_space.md)). Despite
this, the memory addresses will appear contiguous in virtual memory. Each user
space process is presented with the same range of available memory addresses and
the same total capacity.

It is also possible for the kernel to present user space with an available
virtual memory capcacity that exceeds the current physical capacity of the
machine:

> _It's possible for the kernel and all running processes to request more
> byte<!--  -->s of virtual memory than the total size of RAM. In that
> situation, the OS can move move bytes of memory to secondary storage to make
> room in RAM for newly requested memory._

_How Computers Really Work_ (2021) p.206

## Virtual memory and the kernel

The kernel itself utilises virtual memory.

During the [boot_process](Boot_process.md), it runs in physical memory mode
however it rapidly creates a 1:1 mapping of physical to virtual memory for
itself. This direct mapping allows the kernel to easily access any physical
memory location as needed, whilst retaining the benefits of virtual memory.

With its own virtual memory established, it can then build additional virtual
memory structures for itself and user processes.

While the kernel uses virtual memory it can also access physical memory at any
time wherease user space processes can only ever access virtual memory.

The kernel virtual memory has a different range of virtual addresses to work
with than user space virtual memory.

Unlike user space virtual memory, the kernel has access to everything running in
kernel address space whereas processes in user address space are partitioned
from each other with separate address spaces that cannot interact.

In addition to being able to access its own virtual memory (and physical memory,
as required) the kernel can also access any user processes' virtual address.

This said, the virtual memory space of the kernel and the virtual memory space
of the user processes are distinct. It is not the case that the kernel is
superset of all available virtual memory. It can access user space virtual
memory because it sets up the tables and locations, not because it is a subset
of its own virtual memory.

![Virtual memory diagram](../img/virtual-memory-diagram.jpg)


title: Virtual_private_cloud
last_modified: 2024-10-18 18:55:56
body:
# Virtual Private Cloud

AWS VPC is used to create a virtual network. This is typically used in concert
with [[zk/Elastic_Compute_Cloud]] to manage connections to a virtual server both
privately and accross the internet.

You define a network address range and then create subnets for managing
different connections and functionality. You use a public subnet for resources
that must be connected to the internet and a private subnet for resources that
are to remain isolated from the internet.

The diagram below details a basic VPC configuration:

![](../img/aws-vpc-example.png)

- Within a given AWS region we have created a VPC network.
- This comprises public and private subnets
- Both subnets host an EC2 instance
- The public subnet has a bridge to the internet through the Internet Gateway
- Both subnets have a routing table to manage requests and access


title: Creating_a_RESTful_API_GET
last_modified: 2024-10-18 18:55:56
body:
# Creating a RESTful API: `GET` requests

With our GET request we will simply return the array of course objects.

We create an [event emitter](Events%20module.md#event-emitters) and listener
that listens for GET requests on a specified port and sends data in response to
requests.

```js
// Return a value as response from specified URI
router.get("/", (req, res) => {
  res.send(courses);
});
```

Our server is now set up:

![](/img/server-listening.png)

> When creating our API this structure of creating handlers for specific routes
> will be iterated. Every endpoint will be specified with
> `[app].[http_request_type]` and followed by a callback.

We can now call the endpoint:

```js
const getAllCourses = async () => {
  try {
    const resp = await axios.get("http://localhost:3000/api/courses");
    console.log(resp.data);
  } catch (err) {
    console.error(err);
  }
};

getAllCourses();
```

Returns:

```js
[
  { id: 1, name: "First course" },
  { id: 2, name: "Second course" },
  { id: 3, name: "Third course" },
];
```

## Parameters

The previous example serves the entire set of our data. But we will also need to
retrieve specific values, we do this by adapting the GET callback to accept
parameters. These parameters will correspond to the specific entry in our main
data array.

```js
router.get("/:id", (req, res) => {
  res.send(req.params.id);
});
```

We use the `:` symbol in the URI to indicate that we looking to parse for a
specific value in the data. Now if we call `/api/courses/2`, we will get the
second item in the array.

The block above is the most basic format but we would want to add some kind of
error handling, for example:

```js
router.get("/:id", (req, res) => {
  const course = courses.find((c) => c.id === parseInt(req.params.id));
  if (!course) res.status(404).send("A course with the given ID was not found");
  res.send(course);
});
```

## Queries

Whereas parameters return specific data points, queries don't get data they
aggregate or present the data that is returned in a certain way, such as for
instance applying a search function. We indicate queries with a `?` in our URI.
For example: `/api/posts/2018/1?sortBy=name`. To facilitate a request like this
we have to create a GET path that allows for it:

```js
router.get("/:year/:month", (req, res) => {
  res.send(req.query);
})[]();
```

We would get the following back:

```json
{
  "sortBy": "name"
}
```

Again a JSON object with key-value pairs is returned.


title: Atomic_and_molecular_propositions
last_modified: 2024-10-18 18:55:56
body:
# Atomic and molecular propositions

Propositions are expressions **that have truth values**, either true or false.

We call a proposition which does not contain a logical connective (or
'sentential connective') a **simple proposition**.

We call a proposition that does contain a logical connective, a **compound
proposition**.

Simple propositions are represented within a formal language of sentential logic
with a single character, customarily _P_ or _Q_. When we refer to the formal
representation of such propositions in our system of sentential logic (SL) we
call them **atomic propositions**.

Compound propositions consist in single characters for each atomic proposition
that they comprise, combined with a symbol for the logical connective. When we
refer to the formal representation of such propositions in SL we call them
**molecular propositions**.

### Demonstration

Atomic proposition:

```
Socrates was a philosopher.
(P)
```

Molecular proposition:

```
Socrates was a philosopher and a drinker.
(P & Q)
```

Connectives in natural language often obscure the logical basis of the
proposition being expressed (where such a proposition contains a proposition,
i.e. excluding propositions that are _logically indeterminate_. The molecular
proposition is above is such an example. In this instance the proposition can be
expressed more precisely as:

```
Socrates was a philosopher and Socrates was a drinker.
```

Where propositions in natural language cannot be elucidated by the addition of
implied logical connectives in the manner above, they must be treated not as
molecular propositions but as atomic proposition. Example:

```
Two splashes of gin and a few drops of vermouth make a great martini.
```

If we were to formalise this as:

```
Two splashes of gin make a great martini and a few drops of vermouth make a great martini.
```

We would lose the sense of the original and we would not be uncovering any logic
that is in the original.


title: Ohms_Law
last_modified: 2024-10-18 18:55:56
body:
# Ohm's Law

The relationship between
[current](Current.md),
[voltage](Voltage.md), and
[resistance](Resistance.md) is
defined by Ohm's Law:

> The current flowing from one point to another is equal to the voltage accross
> these points divided by the resistance between them.

$$
I = \frac{V}{R}
$$

As an application, consider a circuit with a 9V battery with a 10,000 $\Omega$
resistor attached across its terminals.

The current flowing through the resistor can be calculated as follows:

$$
\frac{9V} {10,000\Omega} = 0.0009 \textsf{A} (0.9 \textsf{mA})
$$


title: Biconditional_Introduction
last_modified: 2024-10-18 18:55:56
body:
# Biconditional introduction

The biconditional means if $P$ is the case, $Q$ must be the case and if $Q$ is
the case, $P$ must be the case. Thus to introduce this operator we must
demonstrate both that $Q$ follows from $P$ and that $P$ follows from $Q$. We do
this via two sub-proofs.

![](/img/bi-intro.png)


title: Invoking_the_shell_in_Python
last_modified: 2024-10-18 19:15:48
body:
# Invoking the shell in Python

```py
import subprocess

try:
    process = subprocess.run(
        ["ls", "-la"],
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
    )
    return process.stdout

except subprocess.CalledProcessError as e:
        return e.stderr.strip()
```


title: Listing_and_navigating_directories_in_the_Shell
last_modified: 2024-10-18 19:16:18
body:
# Listing and navigating directories in the shell

## Listing options

Obviously we know that in order to list the files and sub-directories in our
current directory we use `ls` but here are some of the most useful of the
different modifiers:

- `**ls -a**`
  - list and include hidden dot files
- `**ls -l**`
  - list with user permissions, file-size and date-modified (most detailed)
- `**ls ***`
  - list organised by folders one level deep

## Navigation shorthands

- `cd -`
  - Return to the directory you were last in
- `!!`
  - Repeat the last command


title: Current
last_modified: 2024-10-18 18:55:56
body:
# Current

> Electrical current is the movement of electrons from negatively charged atoms
> to positively charged atoms when an appropriate external force is applied.

Current is the flow of electrons. Charge is the quantity that flows.

> The amount of current is the sum of the charges of the moving electrons past a
> given point.

## Why current exists

Current exists because of the [first law of electrostatics](Coulombs_Laws.md).

When there is an excess of electrons at one terminal (i.e. negatively charged
atoms) and a deficiency of electrons at the other terminal (i.e. positively
charged atoms), a [_difference of potential_](Voltage.md) exists between the two
terminals.

When the terminals are connected to each other via a conductor (e.g. copper
wire) electrons will flow along the conductor. This is provided that there is a
source to supply electrons at one end and remove them at the other. We call this
force the **voltage source**.

_The diagram below illustrates the flow of current where the circles are
electrons knocking into each other and passing current:_

![](/img/charge-cylinder.svg)

> Electrons travel very slowly through a conductor. This is in contrast to their
> intrinsic motion which of course equal to the speed of light (186, 000 miles
> per second).

## Formal expression

We measure **charge** in Coulombs ($C$). A Coulomb is an aggregate of the charge
of thousands of electrons because their individual charge is so small. One
Coulomb is equal to the charge of $6.24 \times 10 ^{18}$ electrons.

We measure **current** in amps. When one coulomb of charge moves past a point in
one second it is called an **ampere** (amp) represented as $A$.

This relationship is captured in the following equation:

$$
I = \frac{Q}{t}
$$

- $I$ = current measured in amps
- $Q$ = quantity of electrical charge measured in coulombs
- $t$ = time

### Application

_Calculate the current in amps if 9 coulombs of charge flow past a point in an
electric circuit in 3 seconds._

$$
I = \frac{9}{3} \\
I = 3  A
$$

## Direction of current

In terms of the physics, current flows due to the movement of charged particles
from atoms which are negatively charged to atoms which are positively charged.
However when it comes to the representation of current in electrical circuits
the convention is to view current as flowing from the positive to the negative
terminal.

This is obviously physically inaccurate however it became the convention before
electrons were properly understood when charge was thought to be a property of
protons. So we are stuck with this convention in electronics.


title: Global_object_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Global object

> In Node every function and variable should be scoped to a module. We should
> not define functions and variables within the global scope.

- In Node the equivalent to the browser's `Window` object is `global`. The
  properties and methods that belong to this method are available anywhere in a
  program.

- Just as we can technically write `Window.console.log()`, we can write
  `global.console.log()` however in both cases it is more sane to use the
  shorthand.

- However if we declare a variable in this scope in browser-based JavaScript,
  this variable becomes accessible via the `Window` object and thus is
  accessible in global scope. The same is not true for Node. If you declare a
  variable at this level it will return undefined.

- This is because of Node's modular nature. If you were to define a function
  `foo` in a module and then also define it in the global scope, when you call
  `foo`, the Node interpreter would not know which function to call. Hence it
  chooses not to recognise the global `foo`, returning undefined.


title: Lambda_programming_model
last_modified: 2024-10-18 18:55:56
body:
# AWS Lambda programming model

The overall architecure consists in the following three processes:

1. Triggers
2. Handler function
3. Code

## Triggers

See [AWS Lambda triggers](Lambda_triggers.md)

## Handler function

See
[AWS Lambda handler function](Lambda_handler_function.md)

## Code

This is just the stuff that runs in the body of the handler or that is called
from the handler body.


title: Querying_a_Mongo_collection
last_modified: 2024-10-18 18:55:56
body:
# Query a Mongo collection with Mongoose

We now have the following entries in our `courses` collection:

```js
{
  name: 'Python Course',
  author: 'Terry Ogleton',
  tags: [ 'python', 'backend' ],
  isPublished: true,
  _id: new ObjectId("62f4e2527ac4aa2c30d41d23"),
  date: 2022-08-11T11:04:50.750Z,
  __v: 0
}

{
  name: 'Javascript Course',
  author: 'Tosh Gnomay',
  tags: [ 'js', 'frontend' ],
  isPublished: true,
  _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
  date: 2022-08-11T11:04:50.750Z,
  __v: 0
}

```

Now we will query the collection. This capability is provided via the Mongoose
schema class we used to create the `Course`
[model](Create_collections_and_documents_with_Mongoose.md#models).
We have the following methods available to use from the schema:

- `find`
- `findById`
- `findByIdAndRemove`
- `findByIdAndUpdate`
- `findOne`
- `findOneAndUpdate`
- `findOneAndRemove`
- ...

The various `find` methods return a value that is promisified.

## Return values with `find`

```js
async function getCourses() {
  const courses = await Course.find();
  console.log(courses);
}
```

## Filter values returned

This will return all the published courses where Tosh Gnomay is the author:

```js
async function getCourses() {
  const courses = await Course.find({
    author: "Tosh Gnomay",
    isPublished: true,
  });
  console.log(courses);
}
```

This time we will filter by the same author but we will add additional
parameters to distinguish:

- only the first ten entries (using `.limit(10)`)
- sort ascending by name (using `.sort({name: 1}))` , to descend we would use
  `-1`)
- only return the properties `name` and `tags` for the item in the collection
  (using `.select({name: 1, tags: 1})`)

```js
async function getCourses() {
  const courses = await Course.find({
    author: "Tosh Gnomay",
    isPublished: true,
  })
    .limit(10)
    .sort({ name: 1 })
    .select({ name: 1, tags: 1 });
  console.log(courses);
}
```

This returns:

```js
[
  {
    _id: new ObjectId("62f4f07a875cff48827b8731"),
    name: "Java Course",
    tags: ["java", "backend"],
  },
  {
    _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
    name: "Javascript Course",
    tags: ["js", "frontend"],
  },
];
```

> Note that the UUID is always returned, whether we specify it or not.

## Querying with operators

So far when filtering we have been doing so with reference to properties that
exist on the document's model (`author`, `isPublished` etc) and we have applied
tranformations on the data returned (sorting, limiting the number or matches
etc.). However we can also apply **operators** within our queries. Operators
allow us to perform computations on the data, for example: for a given numerical
property on an object, return the objects for which this value is within a
certain range.

When we apply operators we use the `$` symbol before the operator and pass the
operator function as an object.

The schema:

```
Model.find( { property: { $operator: conditions } } )
```

### Comparison operators

The following comparison operators are available in MongoDB:

| Operator | Function                  |
| -------- | ------------------------- |
| `eq`     | Equal to                  |
| `ne`     | Not equal to              |
| `gt`     | Greater than              |
| `gte`    | Greater than or less than |
| `lt`     | Less than                 |
| `lte`    | Less than or equal to     |
| `in`     | In                        |
| `nin`    | Not in                    |

We can employ these comparators within a `.find` filter. For example let's
imagine that our `courses` instances have a property of `price`.

To filter course prices that are greater than or equal to 10 and less than or
equal to 29:

```js
Course.find({ price: { $gte: 10, $lte: 20 } });
```

To filter course prices that are either 10, 15 or 20:

```js
Course.find({ price: { $in: [10, 15, 20] } });
```

### Logical operators

When we apply logical operators, we do not apply the query within the main
`find` method. We use a dedicated method that corresponds to the logical
predicate.

For example to query by logical
[OR](Truth-functional_connectives.md#disjunction):

```js
async function getCourses() {
  const courses = await Course.find().or([
    { author: "Tosh Gnomay" },
    { isPublished: true },
  ]);
  console.log(courses);
}
```

We write each disjunct as an object representing the conditions we are filtering
for within an array that is passed to the `.or()` method.

The same syntax applies for conjunction.

### Regular expressions

When filtering by strings we can use Regex for greater power.

Previously we filtered by the author name:

```js
.find({author: "Tosh Gnomay"})
```

To demonstrate regex we could filter by names beginning with `T`:

```js
.find({author: /^T*/})
```

```js
async function getCourses() {
  const courses = await Course.find()
    .or([{ author: "Tosh Gnomay" }, { isPublished: true }])
    .count();
  console.log(courses);
}
```

This will return a number.

### Pagination

We previously used the `limit()` method to control how many matches we return
from a query. We can extend this functionality by creating pagination. This
allows us to meter the return values into set chunks. This is used frequently
when interacting with a database through a mediating RESTful API. For example to
return values from endpoints such as:

```
/api/courses?pageNumber=2&pageSize=10
```

To do this you pass two values as query parameters

```js
const pageNumber = 2;
const pageSize = 10;

async function getCourses() {
  const courses = await Course.find()
    .skip(pageNumber - 1 * pageSize)
    .limit(pageSize);
  console.log(courses);
}
```


title: ps
last_modified: 2024-10-18 18:55:56
body:
# Processes (`ps`)

`ps` allows us to control [user processes](The_kernel.md)
from the shell.

The command in its most minimal application returns the following

```
  PID TTY       TIME     CMD
  2437 pts/2    00:00:01 zsh
  7112 pts/2    00:00:00 ps
```

With the `-e` modifier we can list more processes:

```
 PID TTY          TIME CMD
      1 ?        00:00:05 systemd
      2 ?        00:00:00 kthreadd
      3 ?        00:00:00 rcu_gp
      4 ?        00:00:00 rcu_par_gp
      5 ?        00:00:00 netns
      7 ?        00:00:00 kworker/0:0H-events_highpri
      9 ?        00:00:00 mm_percpu_wq
     11 ?        00:00:00 rcu_tasks_kthread
     12 ?        00:00:00 rcu_tasks_rude_kthread
     13 ?        00:00:00 rcu_tasks_trace_kthread
     14 ?        00:00:08 ksoftirqd/0
     15 ?        00:03:20 rcu_preempt
     16 ?        00:00:00 rcub/0
     17 ?        00:00:00 migration/0
     18 ?        00:00:00 idle_inject/0
     20 ?        00:00:00 cpuhp/0
     21 ?        00:00:00 cpuhp/1
     22 ?        00:00:00 idle_inject/1
     23 ?        00:00:00 migration/1
```

<dl>
<dt>pid</dt>
<dd>Process ID: every currently running process has a unique ID<dd>
<dt>tty</dt>
<dd>The terminal device where the process is running<dd>
<dt>Time</dt>
<dd>The amount of CPU time in minutes and seconds that the process has used so far. The total amount of time that the process has spent running instructions on the processor.<dd>
<dt>cmd</dt>
<dd>The command used to run the program. Note this can change during the running of the program.<dd>
</dl>

## Modifiers

<dl>
<dt><code>ps x</code></dt>
<dd>Show all running processes<dd>
<dt><code>ps ax</code></dt>
<dd>Show all processes not just the ones you, the current user, own<dd>
<dt><code>ps u</code></dt>
<dd>Show detailed info on processes<dd>
<dt><code>ps w</code></dt>
<dd>Show full command names<dd>
</dl>

## Process termination

The general schema is: `kill [pid]`. This allows for process clean-up. If this
doesn't succeed you can force with `KILL [pid]` which will terminate the process
immediately but is obviously more risky.

We can also start/stop processes with modifiers on `kill`:

- `kill -STOP pid`
- `kill -CONT pid`


title: Operating_system_API
last_modified: 2024-10-18 18:55:56
body:
# Operating system API

A user can interact with the operating system either via the GUI or the
[shell](Intro_to_the_Unix_shell.md). (Both ultimately access the OS via the
shell since the UI is an abstraction layer of the shell.)

When _programs_ interact with the operating system they use the **operating
system's API** directly. The GUI and shell also invoke the OS API but the access
is mediated.

Every OS has an API. This specification details how a program should interact
with the OS, exposing functions, properties and data types.

Whether using the GUI or a terminal emulator, the shell translates the user's
commands into API calls. The API the invokes internal operating system code to
perform the action.

![OS API diagram](../img/OS-api.svg)

## Example: opening a file

A user can use a file explorer and the mouse to open a file. Or they can open
the file by invoking it from the terminal.

A running application doesn't have to do this. If it's remit includes opening
files, it can do so by calling the OS API.

On a Unix-like system the applicaton would use the `open` API function to open
the file:

```
open("foo.txt", 0_WRONLY|0_CREAT)
```

This command makes the action write-only and creates the file because it does
not yet exist. When the user opens a file in their File Explorer, the
application translates their graphical actions into this API call.

## Different OSs have different APIs

Unix-like and Linux operating systems use variations on the **Portable Operating
System Interface** (POSIX) standard. This defines the OS API and also the rules
for the shell's behaviour and its included utilities.

Variations on this include _Cocoa_, macOS's API and Android's _Android Platform_
API.

Windows has its own API called _The Windows API_. The original version was
16-bit called _Win16_, then when it moved to 32-bits it became _Win32_. When it
moved to an x86 [instruction_set_architecture](Instruction_set_architectures.md)
it became _Win64_. Starting with Windows 10, it introduced the _Universal
Windows Platform_ which aims to make app development consistent accross
different devices that run Windows.


title: Intro_to_the_Unix_shell
last_modified: 2024-10-18 19:15:25
body:
# Introduction to the Unix shell

## Unix based systems

Many operating systems are based on the UNIX software architecture. macOS/OSX
(Darwin) and GNU/Linux are two very popular examples. Most web servers run a
version of Linux as their native OS thus a knowledge of command line for UNIX
systems is invaluable for web developers. Windows systems are not UNIX based so
everything that is written here is not applicable to the Windows command line
program Command Prompt although there are obvious conceptual overlaps.

UNIX was initially developed by AT&T and is still owned by them. GNU (the basis
for Linux) is a recursive acronym for ’GNU is not UNIX’. Functionally it is the
same as Unix however, it just doesn’t contain the proprietary code.

## Key terms

### Kernal

The kernel is the central part of an operating system. It manages the operations
of the computer and the hardware; most notably memory and CPU time. There are
two types of kernels: a **micro-kernel**, which only contains basic
functionality; and a **monolithic kernel**, which contains many device drivers.

### Shell

A shell is a user interface for access to an operating system’s services. In
general, operating system shells use either a command-line interface or GUI,
depending on a computer’s role and particular operation. It is named a shell
because it is the outermost layer around the operating system kernel

### Bash

Bash is a Unix shell and command language written by Brian Fox for the GNU
Project as a free software replacement for the Bourne shell. First released in
1989, it has been distributed widely as the default login shell for most Linux
distributions and Apple’s macOS.

## What is the command line?

Command line is both a general computing concept and a specific utility. In its
general sense, engaging with a computer via command line means inputting
abbreviated written commands into a console or terminal window on a computer.
The computer then runs these commands on the basis of the instructions you have
given.

You can get the computer to ‘do things’ (make files, connect to networks etc)
via command line and you can use it to check the status of systems within your
computer.

This mode of engagement contrasts with the engagement facilitated by modern
graphical user interfaces (GUIs) where the user navigates via a combination of
keyboard and mouse inputs and interacts with windows whose functionality is
usually self-explanatory and therefore more user-friendly. Command line predates
GUIs but it is considered a more efficient and expansive means of interacting
with the whole of your computer especially if you are a developer or programmer.

In the more specific sense, the ‘command line’ refers to the location in the
console window where you input your commands. The command line consists in a
user name and the current directory you are in followed by a dollar sign and a
cursor waiting for input.

## Basic orientation

When you are using command line you are always situated somewhere within a file
system. Typically this will be your own user files. directory structure By
default you are always in your home directory, this is represented by the tilda
symbol: `~`. This is why you see the tilda symbol as part of the command line.
In command line, we do not use the term ‘folders’, instead they are called
directories. (I will follow this convention from hereon.) You do not have to
worry too much about remembering the names of specific folders and files you can
always ask the computer to display them to you by using `ls` argument or `pwd`.

## Command line syntax

The syntax of the language used to input commands is analogous to the grammar of
natural languages. We have a verb that is operative on an object/noun and which
can be modified through adverbs. The syntax of a command sequence is as follows:

1. Command (verb): what we want to do
1. Option (adverb): modifying the command - always starts with a hyphen
1. Argument (noun/object): what we want our command to operate on

We will see that not all commands require arguments, but this is the general
structure


title: Swap_space
last_modified: 2024-10-18 18:55:56
body:
# Swap space

A swap partition is a partition on a disk that is not intended to be used as a
filesystem. Instead, it is a part of the disk that is used to augment the main
memory.

If you run out of memory and have set up a swap partition, the OS will be able
to move pieces of memory to and from disk storage. This is called _swapping_
because pieces of idle programs are swapped to the disk in exchange for active
pieces residing on the disk.

## View current swap usage

If you have a swap space established, the command `free` will show current
usage:

```bash
free
               total        used        free      shared  buff/cache   available
Mem:        16099420     3031572    10157652     1153144     2910196    11605820
Swap:        3145724           0     3145724
```

## Create a swap partition

To use an existing disk partition as a swap you can run the command
`mkswap [device]` and then `swapon [device]` to register the space with the
[kernel](The_kernel.md).

### Add to `fstab`

You will want the swap to be activated every time the OS boots so add the
following line to the [fstab](Filesystems.md#fstab),
where `/sda3` is used as the example partition:

```bash
/dev/sda3e none swap sw 0 0
```

## Create a swap file

// Add info here


title: Expansions_and_substitutions
last_modified: 2024-10-18 18:55:56
body:
# Expansions and substitutions

Bash is weird in that parentheses, braces and brackets are used not just as
markers for different code blocks but as the designators of commands in their
own right. The type of bracket you use effects how your input is interpreted.

Below are the main forms of expansion and substitution:

| Representation | Name                 |
| -------------- | -------------------- |
| `~` .          | Tilde expansion      |
| `{..}`         | Brace expansion      |
| `${...}`       | Parameter expansion  |
| `$(...)`       | Command substitution |
| `$((...))`     | Arithmetic expansion |

## Brace expansion: `{..}`

Brace expansion is for changing a smaller part of a greater whole
programmatically. This is best understood by looking at examples:

```
echo c{a,o,u}t
cat cot cut
```

```
echo /tmp/{1..3}/file.txt
/tmp/1/file.txt  /tmp/2/file.txt /tmp/3/file.txt
```

```bash
echo {1..5}
1 2 3 4 5

echo {5..1}
5 4 3 2 1

echo {a...c}
a b c
```

We can also set sequences. If we wanted to count to twenty in intervals of two

```bash
echo {1..20..2}
1 3 5 7 9 11 13 15 17 19
```

> Note that we type _two_ dots **not** an elipsis

### Example use case

We might use brace expansion to generate sequential file names using a
pre-defined naming scheme, eg.

```
touch file_{01..12}{a..d}
ls

file_01a
file_01b
file_01c
file_01d
file_02a
file_02b
...
file_12d
```

The syntax here basically means: for each of the elements in the first list, run
the second list against them.

## Parameter expansion: `${...}`

We use most frequently for returning the value of stored
[variables](Variables_and_data_types_in_Bash.md).
Techically we do not have to use the braces, we can retrieve with just `$var`
however it's better to use them to minimise interpretation fuck-ups which happen
a lot.

When the braces are used, this allows us to transform the values before they are
returned such as only returning from the 6th character: `${var:6}`.

## Command substition: `$(...)`

Command substitution (circle-brackets) allows us to put the output of one
command inside another. Bash runs the bracketed command in a
[sub-shell](Shell_sessions.md) and then returns it
to the main user shell.

For example:

```bash
echo "The current directory is $(pwd)."
```

## Arithemtic expansion: `$((...))`

We use arithmetic expansion when we want to calculate numerical values

See
[Working with numbers in Bash](Working_with_numbers_in_Bash.md)
for more.


title: Boolean_functions
last_modified: 2024-10-18 18:55:56
body:
# Boolean functions

An example of a Boolean function:

$$
f(x,y,z) = (x \land y) \lor (\lnot(x) \land z )
$$

Here is a work through where $f(1, 0, 1)$:

- The first disjunction : $\lnot(x) \land z$ is false because $x$ is 1 and $z$
  is 0
- The second disjunction: $x \land y$ is false because $x$ is 1 and $y$ is 1
- The overall function returns false because the main connective is disjunction
  and both of its disjuncts are false

We can compute all possible outputs of the function by constructing a
[trkjuth table](Truth-tables.md) with each possible
variable as the truth conditions and the output of the function as the truth
value:

| $x$ | $y$ | $z$ | $f(x,y,z) = (x \land y) \lor (\lnot(x) \land z )$ |
| --- | --- | --- | ------------------------------------------------- |
| 0   | 0   | 0   | 0                                                 |
| 0   | 0   | 1   | 1                                                 |
| 0   | 1   | 0   | 0                                                 |
| 0   | 1   | 1   | 1                                                 |
| 1   | 0   | 0   | 0                                                 |
| 1   | 0   | 1   | 0                                                 |
| 1   | 1   | 0   | 1                                                 |
| 1   | 1   | 1   | 1                                                 |


title: Mainframe_computers
last_modified: 2024-10-18 19:16:47
body:
# Mainframe computers

A mainframe computer, also known as a "big iron" is a high performance computer
used for resource-intensive tasks that require greater security and availability
than smaller scale machines. They are typically used for centralised rather than
distributed computing.

The heyday of mainframes was before the mini- and micro-computer revolution but
they are still used.

IBM remains the main manufacturer and service provider for mainframes. Example
use cases include banks who need to process large volumes of transatction and
high frequency tranding; government departments, the military and internal
revenue who require huge databases.


title: Mapped_types_in_TS
last_modified: 2024-10-18 18:55:56
body:
# Mapped types in TypeScript

A mapped type is a way to create new types based on existing ones by
transforming their properties

As it works on a single type and typically narrows or limits the properties it
works in a way that is opposite to a [union]() or [intersection]() type.

> Mapped types are an example of when `type` is preferable to `interface`, since
> you cannot generate mapped types as interfaces, although you may generate a
> mapped type from an interface.

For the demonstrations we will use the following type as the example that we
will map from:

```ts
type Person = {
  name: string;
  age: number;
  city: string;
  country: string;
};
```

## Main varieties of mapped types

### Read only

Creates a type with all properties of the given type set to `readonly`:

```ts
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type ReadonlyPerson = Readonly<Person>;
```

This is equivalent to:

```ts
type ReadonlyPerson = {
  readonly name: string;
  readonly age: number;
  readonly city: string;
  readonly country: string;
};
```

### Partial

Creates a type with all properties of the given type set to optional.

```ts
type Partial<T> = {
  [P in keyof T]?: T[P];
};

type PartialPerson = Partial<Person>;
```

This is equivalent to:

```ts
type PartialPerson = {
  name?: string;
  age?: number;
  city?: string;
  country?: string;
};
```

### Pick

This is useful when you want to create a new type based on a subset of
properties from an existing type.

```ts
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type PersonNameAndAge = Pick<Person, "name" | "age">;
```

This is equivalent to:

```ts
type PersonNameAndAge = {
  name: string;
  age: number;
};
```

### Record

Creates a type with keys of the given type and values of the specified type. It
is a way of shoehorning keys from an existing type with new values.

Basic syntax:

```ts
Record<Keys, ValueType>;
```

Example:

```ts
type UserRole = "admin" | "user" | "guest";

// Create a Record type to store user role descriptions
type UserRoleDescriptions = Record<UserRole, string>;

// Create an object that implements the UserRoleDescriptions type
const roleDescriptions: UserRoleDescriptions = {
  admin: "Has full access to the system",
  user: "Can access limited resources",
  guest: "Can view public resources only",
};
```

Here is a simpler example

```ts
type Person = {
  name: string;
  nationality: string;
};

type PersonInstance = Record<string, Person>;
const thomasInstance: PersonInstance = {
  thomas: {
    name: "Thomas",
    nationality: "British",
  },
};
```

### Exclude

Creates a type by excluding specific properties from the given type.

```ts
type Exclude<T, U> = T extends U ? never : T;

type KeysWithoutAge = Exclude<keyof Person, "age">;
```

This is equivalent to:

```ts
type KeysWithoutAge = "name" | "city" | "country";
```

### Extract

Creates a type by extracting specific properties from the given type. Basically
the opposite operation to Exclude.

```ts
type Extract<T, U> = T extends U ? T : never;

type NameKey = Extract<keyof Person, "name">;
```

This is equivalent to:

```ts
type NameKey = "name";
```

### Non-nullable

Creates a type by removing null and undefined from the given type.

```ts
type NonNullable<T> = T extends null | undefined ? never : T;

type NullablePerson = {
  name: string | null;
  age: number | null;
  city: string | null;
  country: string | null;
};

type NonNullablePerson = NonNullable<NullablePerson>;
```

Equivalent to:

```ts
type NonNullablePerson = {
  name: string;
  age: number;
  city: string;
  country: string;
};
```


title: Case_statements_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Case statements in Bash

Usage against a variable

```sh
animal="dog"
case $animal in
    bird ) echo "Avian";;
    dog|puppy ) echo "Canine";;
    * ) echo "No match";;
esac
```

Usage as part of a function:

```bash
function convertCharToInt {
    case $1 in
        A|X )
            echo 1 ;;
        B|Y )
            echo 2 ;;
        C|Z )
            echo 3 ;;
        *)
            echo ;;
    esac
}
```

Usage:

```bash
declare -i intValue = $(convertCharToInt B)
```


title: Audio_file_formats
last_modified: 2025-01-02 17:31:38
body:
# Audio file formats

## CD quality

We can use CD's as the digital gold standard as the best digital quality
available (to consumers).

CDs store audio in uncompressed PCM (Pulse Code Modulation) format.

They have a sampling rate of 44.1kHz, which is done in two channels to enable
stereo.

## What lossy formats entail

A conversion to MP3 from, for example, a CD source is always a one-way process
and is not reversible. Once information is discarded in the compression process,
it cannot be retrieved.

This is obviously in contrast to lossless methods like FLAC where the original
CD audio can always be reconstructed.

It follows from the above that if you repeatedly encode a CD source to MP3, it
will deteriorate in quality since more data is being removed each time.

## Major audio formats

### WAV (Waveform Audio File Format)

- CD-quality encoding with no compression
- Bit-for-bit identical to the CD source
- Historically developed for Windows machines but can play on all operating
  systems

### FLAC (Free Lossless Audio Codec)

- Basically the same as WAV but in a (losslessly) compressed format
- The difference between a novel in a text file (WAV) and as a zipped file

### MP3 (MPEG-1 Audio Layer MP3)

- Lossy format.
- When a WAV file (or other lossless format) is converted to MP3 a Fast Fourier
  Transform analysis is performed to determine the frequency of certain sounds
- This is used by the encoder to decide which parts of the sound are
  imperceptible and thus which can be discarded to reduce the file size. This is
  done through the application of psycho-acoustic models.
- The remaining data is then compressed
- Examples of the data reduction applied:

  - Removing frequencies that humans cannot hear
  - Removing quieter sounds that are masked by louder sounds
  - Combining similar frequencies
  - Reducing stereo information where it is less noticeable

### OGG: Ogg Vorbis

- An open-source alternative to MP3
- Typically achieves better quality than MP3 at the same bit rate, especially at
  very high/ low frequencies
- Also better stereo handling at low frequencies
- Uses a more modern psycho-acoustic model

## Variable and constant bit rates

For lossy formats like MP3, the amount of data that is being encoded from the
uncompressed source is expressed via the unit of "bit rate": **how many
thousands of bits are being used to represent each second of audio**.

There are two methods of encoding that impact on the bit rate.

With _variable bit rate_ encoding, the encoder dynamically adjusts the bit rate
depending on what is happening in the music. During complex passages (e.g. a
full orchestra) it uses a higher bit rate to capture the detail. During simpler
passages (like a single instrument) it uses lower bit rates since less data is
needed and during silence it can drop to very low bit rates.

_Constant bit rate encoding_ uses the same bit rate throughout, it is
consequently less efficient.

When talking about the quality of MP3s there are generally two bit rates cited:

- ~128kbps: acceptable but significantly reduced
- 320kbps: the highest quality you can get whilst still using a lossy method
  like MP3

With VBR, these are sometimes expressed as an average.

Subjectively, A 128kbps MP3 might sound "underwater" or "swishy", while a
320kbps version would preserve much more detail.

Still, the bit-rate of a CD is 1411kbps! A 128kb/s MP3 is therefore only
capturing about 9% of CD quality and a 320kbps MP3 is capturing about 23% of CD
quality.

## Streaming services

Spotify uses Ogg Vorbis throughout but uses different bit rates for its
different tiers. The free tier has a range from 24-160kb/s at VBR with the
option of 320kb/s on the premium tier.

Other services offer FLAC or FLAC-equivalent quality at their most expensive
tiers (Apple Music, Amazon Music, Tidal).

Og Vorbis is particularly well-suited to streaming. It can seamlessly switch bit
rates during the stream which is beneficial with changeable network conditions.
Plus data is organised into independent packets so if a packet is lost there is
no perceptible difference.


title: Child_to_parent_data_flow_in_React
last_modified: 2024-10-18 18:55:56
body:
# Child to parent data flow

Despite React having a uni-directional, downwards data-flow, it is sometimes
necessary to pass events and data from a child back up to the parent. This need
can arise when you want to modularize functionality within a child component
rather than have everything happening in the parent, and you don't want to use a
common shared higher context.

For the example we will use the standard click incrementer.

We have a counter on the parent that is updated in response to a click event in
the child component.

Our parent component is `App` and the child component is `Child`

```jsx
export default function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>{count}</p>
      <Child count={count} setCount={setCount} />
    </>
  );
}

const Child = ({ count, setCount }) => {
  return <button onClick={() => setCount(count + 1)}>Increment</button>;
};
```

So the overall state and updater function exists on the parent. The child is
able to access this state by virtue of receiving `{count, setCount}` as props.
It can therefore manipulate this state and have it be reflected in the parent.

It is not necessary to pass the state variable every time. You could just pass
the updater. We have passed the `count` variable here because the child needs
access to the current value, in order to be able to increment it.


title: File_operations_in_Python
last_modified: 2024-11-03 14:55:44
body:
# File operations in Python

Most create, delete, move etc operations invoke the inbuilt `os` module.

// Add directory CRUD operations in Python

## Renaming files (moving)

```py
import os
os.rename('original-file-name.txt', 'new-file-name.txt')
```

## Deleting files

```py
import os
os.remove('file-name.txt')
```

## Check file exists

```python
import os

file_exists = os.exists('/file/path')

```


title: Four_bit_adder
last_modified: 2024-10-18 18:55:56
body:
# Four-bit adder

A single
[half adder](Half_adder_and_full_adder.md#half-adder)
and
[full adder](Half_adder_and_full_adder.md#fufll-adder)
allows us to calculate the sum of two 1-bit numbers, but this is not much use in
practice. To approximate what is really happening at the circuit level in
computers we need to be able to add bigger binary numbers. We will demonstrate
how this can be achieved for a four-bit number (nibble) using repeated full
adders and half adders.

We want to be able to calculate the following sum:

```
0010
0011
____
0101
```

We will achieve this by using three full adders and one half adder, moving from
right to left. The half adder will be used at the beginning to calculate the
least significant bit as it will have no carry-in. The subsequent three bits
will all be added using a full adder.

Let's walk through the process:

>

1. HA receives the bits $0$ and $1$ as inputs. It outputs $1$ as the sum bit and
   $0$ as the carry-out.
2. FA1 receives $0$ as the carry-in bit plus $1$ and $1$ as its input. This
   means it has the following calculation to execute: $1 + 1 + 0$. This gives
   $0$ as the sum bit and $1$ as the carry-out bit.
3. FA2 receives $1$ as the carry-in (the carry-out from FA1) plus $0$ and $0$ as
   its own inputs. $0 + 0 + 1$ gives us $1$ as the sum bit and $0$ as the
   carry-out.
4. Finally FA3 receives $0$ as its carry-in plus $0$ and $0$ as its inputs.
   $0 + 0 + 0 = 0$, therefore its sum bit is $0$ and the overall sum of the four
   bits is $0101$. There is no carry out as there are no more bits to add.

## Ripple carry adder

We notice that as the calculation proceeds, the carry bits propagate or _ripple_
through the circuit. For this reason, a four-bit adder constructed in the manner
of this circuit is called a **ripple carry adder**.

There are two important consequences to note about this type of circuit:

- Each carry bit that ripples to the next full adder introduces a small delay.
  Therefore extending the circuit to handle more bits will make the circuit
  slower overall.
- Because the value of the bits changes through the course of the ripple, the
  output of the circuit will be innacurate until all the carry bits have had
  time to propagate.


title: Mixed_and_improper_fractions
last_modified: 2024-10-18 18:55:56
body:
# Mixed and improper fractions

## Improper fractions

- Proper fraction:
  - The numerator is smaller than the denominator
  - E.g. $\frac{2}{3}$, $-\frac{5}{10}$
- Improper fraction
  - The numerator is greater than the denominator
  - E.g. $\frac{3}{2}$, $-\frac{5}{4}$

## Mixed fractions

A mixed fraction is part whole number, part fraction. For example:
$5 \frac{3}{4}$.

It means, in effect: $5 + \frac{3}{4}$

## Converting mixed fractions into improper fractions

Mixed fractions are hard to calculate with. We need some way to convert them to
fractions. We can do this by converting them to improper fractions.

With the example $4 \frac{7}{8}$, we know this means $4 + \frac{7}{8}$. We need
to express the amount 4 in terms of eighths. It would be 4 lots of $\frac{8}{8}$
given that 4 is a whole number not a fractional amount. Thus the process would
be:

$$
    \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{7}{8}
$$

But we know that when we
[add fractions with a common denominator](Add_Subtract_Fractions.md#adding-subracting-fractions-with-common-denominators),
we only add the numerators, not the denominators. Thus the calculation would
actually be:

$$
\frac{8 + 8 + 8 + 8 + 7}{8} = \frac{39}{8}
$$

Addition helps to explain the concepts underlying the procedure but it is more
efficient to use multiplication.

The procedure is as follows:

1. Multiply the whole number part by the denominator
2. Add the numerator
3. Place the result over the denominator

Thus:

$$
    4 \frac{7}{8} = \frac{(4 \cdot 8) + 7 }{8}
$$

## Converting improper fractions into mixed fractions

It is quite obvious how to reverse the process and turn an improper fraction
into a mixed fraction.

Take $\frac{27}{5}$. We work out how many times the numerator is divisible by
the denominator and make that the whole number. The remainder is then left as
the fractional part.

$$
\begin{split}
\frac{27}{5} = 27 \div 5  \\
= 5 r 2 \\
= 5 \frac{2}{5}
\end{split}
$$

## Multiplying and dividing by mixed fractions

Now that we know how to convert mixed fractions into improper fractions, it is
straight forward to multiply and divide with them. We convert the mixed fraction
into an improper fraction and then divide and multiply as we would with a proper
fraction.

### Demonstration of multiplication

Calculate $-2\frac{1}{12} \cdot 2 \frac{4}{5}$:

1. First convert each mixed fraction into an improper fraction:
   $$
     \begin{split}
     -2\frac{1}{12} = -2 \cdot -12  \\
     = 24 + 1 \\
     = - \frac{25}{12}
     \end{split}
   $$

$$
\begin{split}
  2 \frac{4}{5} =2 \cdot 5 \\
  = 10 + 4 \\
  = \frac{14}{5}
\end{split}
$$

2. Then carry out the multiplication
   [using factorization](Multiplying_fractions.md#prime-factorisation-in-place):

   $$
     \begin{split}
     - \frac{25}{12} \cdot \frac{14}{5} = \\
    - \frac{(5 \cdot 5) \cdot (7 \cdot 2)}{(3 \cdot 2 \cdot 2) \cdot (5)} = - \frac{5 \cdot 7 }{2 \cdot 3} \\
     \end{split}
   $$

3. Then simplify:

   $$
     - \frac{35}{6}
   $$

4. Finally, convert back into a mixed fraction:

$$
  \begin{split}
  - \frac{35}{6} = -35 \div 6 \\
  -  5 r 5 = \\
  - 5 \frac{5}{6}
  \end{split}
$$

## Demonstration of division

Again we convert the mixed fraction into an improper fraction and then follow
the requisite rule, in the case of division this is to
[invert and multiply](Dividing_fractions.md#formal-specification-of-how-to-divide-fractions').

Calculate $-4 \frac{4}{5} \div 5 \frac{3}{5}$.

1. Convert to improper fraction:
   $$
      \begin{split}
        -4 \cdot 5 = \\
    -20
   \end{split}
   $$

## Adding and subtracting mixed fractions


title: Signed_and_unsigned_numbers
last_modified: 2024-10-18 18:55:56
body:
# Signed and unsigned numbers

## Summary

- To represent negative integers in binary we use signed numbers._Signed binary_
  includes negative integers, _unsigned binary_ does not.

- There are different methods of implementing the encoding of signed numbers.
  Two prominant approaches are **two's complement** and **signed magnitude
  representation**.

## Related notes

[[Twos_complement]], [[Binary_encoding]], [[Signed_magnitude_representation]]


title: Additive_identity
last_modified: 2024-11-04 15:19:09
body:
# Property of Additive Identity

**Let $a$ represent any member of $\mathbb{W}$ or $\mathbb{Z}$ then:**

$$ a + 0 = a $$


title: Using_GraphQL_with_Node
last_modified: 2024-10-18 18:55:56
body:
# Using GraphQL with Node.js

## Create a basic Express server

First we create a basic server in Node using Express:

```js
import express from "express";

app.get("/", (req, res) => {
  res.send("Graph QL test project");
});

app.listen(8080, () =>
  console.log("Running server on port localhost:8080/graphql")
);
```

## Add GraphQL as middlewear

Next we introduce GraphQL as a piece of Node.js
[middlewear](Middleware_in_NodeJS.md), with the
`app.use()` method.

```js
import { graphqlHTTP } from "express-graphql";

app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema,
    rootValue: resolvers,
    graphiql: true,
  })
);
```

- `schema` is a reference to our GraphQL schema - the structure of the fields
  that define our server.
- `rootValue` is a reference to our resolvers.
- `graphiql` is the GUI tool that will be served from the GraphQL endpoint at
  `localhost:8080/graphql`. This tool enables us to interrogate our data using
  the defined schema and see what data we would get back from frontend queries.


title: Turing_machines
last_modified: 2024-10-19 10:00:57
body:
# Turing Machines

## What is a Turing Machine?

Turing Machine is a machine that contains mutable state, executes sequences of
simple instructions that read and write that state, and can pick different
execution paths depending on the state (via conditional branch instructions.)

This is a general expression, it is typically expanded as follows.

The machine consists of an infinitely long tape, that has been divided up into
cells. Each cell can contain either a 1, a 0 or an empty space. Above one cell
of the tape is a head, which can either move left or right, and can read the
symbols written in the cells. The head is also capable of erasing symbols and
writing new symbols into the cells.

![Turing_machines_01.gif](Turing_machines_01.gif)

The direction that the head moves, which values it erases, and which values it
writes in, are dependent on a set of instructions provided to the machine.

Different sets of instructions can be divided into **states.** States are like
sub-routines and can themselves feature as part of instructions.

For example:

### State 2

- If 0 then erase
- Write 1 then move right
- Go to state 5

### State 5

- If 1, then erase
- Write 0 then move left
- Go to state _n_

Alan Turing proved that **any problem that is computable** can be computed by a
Turing Machine using this simple system.


title: journald
last_modified: 2024-10-18 18:55:56
body:
# `journald`

`journald` is a program that comes as default with [systemd](systemd.md). It is
a service for collecting and storing system-level log data. I keeps a track of
all [kernel](The_kernel.md) processes. It is invaluable when tracing the source
of problems and errors that may arise on the system level. It keeps a track of
all kernal processes.

![](/img/journald.png)

## `journalctl`

We use `journalctl` to access the logs. The command by itself outputs the entire
log which will be huge and hard to scroll through. We can refine the results
with modifiers.

### View logs for a specific process with pid

```bash
journalctl _PID=1234
```

### View logs for a specific time period

This can be really helpful since you can bracket the most recent events which
will be more memorable.

```bash
journalctl -S -1h
```

### View logs for a specfic systemd unit

```bash
journalctl -u [unit_name] -e
```

### View boot logs

```bash
journalctl -b
```

#### Identify specific boot

```bash
journalctl --list-boots

```

### List only kernel entries to the journal

```bash
journalctl -k

```


title: Create_an_SQL_table
last_modified: 2024-10-18 18:55:56
body:
# Create an SQL table

We create tables in an SQL database with the `CREATE` command.

Below is an example of this in practice. Each field corresponds to a column. We
specify the name of the field and its corresponding
[data type](Data_types_in_MySQL.md). Every table must have a
**primary key**. In the example, `employee_id` is the primary key.

```sql
CREATE TABLE employee (
    employee_id text PRIMARY KEY,
    first_name text,
    surname text,
    address_number integer,
    address_1 text,
    address_2 text,
    locality text,
    region text,
    postal_code text,
    phone_number text,
    days_per_week real
    );
```

## Check table metadata

We can use `DESCRIBE [table_name]` any time we want to list out the data types
and other metadata about the table.

We can use `SHOW TABLE STATUS`/


title: Strings_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Strings in Python

> Generally, anything that changes a string will be a method on the `str` class,
> rather than a built-in function like `len()`, as such it will use dot notation

- Strings are **immutable**: string operations produce a new string.

```python
# Working with Strings

my_variable = 'Bob'
print(my_variable)
# Bob

my_variable = "Eloise"
print(my_variable)
# Eloise

# A multi line string
my_variable = """
Hello
  World
"""
print(my_variable)
"""
Hello
  World
"""

my_string = 'Hello World'
print(len(my_string))
# 11

string_1 = 'Good'
string_2 = " day"
string_3 = string_1 + string_2
print(string_3)
# Good day

msg = 'Hello Lloyd you are ' + str(21)
print(msg)
# Hello Lloyd you are 21

# Range of String operations
msg = 'Hello World'
print(msg.replace("Hello", "Goodbye"))
# Goodbye World

print('Edward Alan Rawlings'.find('Alan'))
# 7

print('Edward John Rawlings'.find('Alan'))
# -1

print('James' == 'James') # prints True
print('James' != 'John') # prints True

print("msg.startswith('H')", msg.startswith('H'))
# msg.startswith('H') True

print("msg.endswith('d')", msg.endswith('d'))
# msg.endswith('d') TRUE

print('some_string.upper()', msg.upper())
# some_string.upper() HELLO WORLD

print('sub string: ', 'Hello-World'[1:5])
# sub string: ello

# String interpolation
user_age = input("Please enter your age: ")
print(f'You are {user_age}')
```

## `str.split()`

The `split()` function in Python is used to divide a string into multiple parts
at the occurrence of a given separator. This function returns a
[list](Lists_in_Python.md) of substrings.

### General syntax

```py
str.split(separator, maxsplit)
```

- The `separator` is optional. It specifies the separator to use when splitting
  the string. If no separator is provided, it will default to using whitespace.

- `maxsplit` is also optional and specifies how many splits to do. Default value
  is -1, which is "all occurrences".

### Examples

```py

text = "Hello world, how are you?"

# Default usage:
x = text.split()
print(x)
# ['Hello', 'world', 'how', 'are', 'you?']

# Using a specific separator
x = text.split(",")
print(x)
# ['Hello', 'world how are you?']

# Specifiying a maxplit value
x = text.split(" ", 1)
print(x)
# ['Hello']
```


title: AWS_architecture_hierarchy
last_modified: 2024-10-18 18:55:56
body:
# AWS architecture hierarchy

From bottom up:

```mermaid
flowchart TD
    Data centres --> Availability Zones--> Regions
```

| Entity             | Description                     |
| ------------------ | ------------------------------- |
| Data center        | Warehouse full of servers       |
| Availability Zones | A cluster of data centers       |
| Region             | A cluster of Availability Zones |


title: Lambda_handler_function
last_modified: 2024-10-18 18:55:56
body:
# AWS Lambda handler function

Every Lambda function begins the same way with a handler function. In NodeJS:

```js
module.exports.handler = function(event, context, callback){...}
```

The handler is the entry point for the Lambda. It is a function that Lambda can
call to start the execution of your code when an event triggers your Lambda
function.

You may put your whole code in the body of the handler, or you may call other
modules and keep the handler clean and focused on bootstrapping.

The `module.exports` part is just the standard way of exporting a module in
Node. `handler` is a property that is being exported.

You always have access to the parameters `event`, `context` and `callback`.

- `event`
  - The triggering event of the Lambda function stored as an object. The
    object's contents will be different depending on the trigger. It could be
    any AWS service that serves a trigger (S3, DynamoDB, API Gateway etc).
  - For example, if the triggering function is a request to API Gateway, the
    `event` object will contain information about the HTTP request such as
    headers, path, and the request body.
- `context`
  - contains information about the runtime environment and the current execution
    of the Lambda function. The context object provides properties and methods
    that you can use to interact with the AWS Lambda service and the current
    invocation.
- `callback`
  - an optional parameter that represents a callback function provided by AWS
    Lambda. The callback function allows you to signal the completion of your
    Lambda function's execution and return a response or an error. The callback
    function accepts two arguments: error and result. If the first argument is
    not null, AWS Lambda treats it as an error, and the Lambda function
    invocation fails. If the first argument is null, AWS Lambda treats the
    second argument as the result and considers the invocation successful. Using
    the callback function is more common in non-async handler functions. When
    you use async functions, you can return a response or throw an error
    directly, without using the callback function.

### Full example:

In JavaScript:

```js
module.exports.handler = async (event, context) => {
  // Your logic to handle the incoming event
  // For example, you can call other AWS services, process the event data, etc.

  // Return a response
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: "Your Lambda function has successfully executed!",
    }),
  };
};
```

In Python:

```py
import json

def handler(event, context):
    # Your logic to handle the incoming event
    # For example, you can call other AWS services, process the event data, etc.

    # Return a response
    response = {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'Your Lambda function has successfully executed!'
        })
    }
    return response
```


title: Utilities_operators_flags
last_modified: 2024-10-19 10:01:23
body:
# Utilities, operators, flags in Bash

The following are useful built-in utility methods that you can use for checking
and validation in the course of your bash scripts.

## Flags

### Prevent newline

Prevent bash from adding a new line after an echo:

```bash
echo 'Your name is Thomas'
echo 'and you are 33 years old'

# Your name is Thomas
# and you are 33 years old
```

```bash
echo -n 'Your name is Thomas '
echo 'and you are 33 years old'

# Your name is Thomas and you are 33 years old
```

## Operators

### Mathematical

```bash
-lt , -gt,
```


title: Example_scenario_internet_data_transfer
last_modified: 2024-10-18 18:55:56
body:
# Example scenario of data transfer accross the internet

![Path of a network request accross the internet](../img/network-request-layers.png)

![All layers of the IP](../img/all-layers-of-IP.png)

- A client device is connected to a wireless WiFi network.
- This network is connected to the internet via a router.
- Elsewhere on the internet is a server also connected to the internet via
  router.
- A user of the client device opens a web browser and requests a web page hosted
  on the server (we will assume it already knows the IP address)
- The web browser knows HTTP - a protocol of the
  [Application Layer](Application_Layer_of_Internet_Protocol.md) - and forms an
  HTTP request intended for the destination server.
- The browser hands off the HTTP request to the TCP/IP software stack of the
  device's [operating system](Basic_model_of_the_operating_system.md), asking
  that the data be delivered to the server on its IP address and at port 80.
- The TCP/IP software stack on the client OS encapsulates the HTTP payload in a
  TCP segment (at the
  [Transport Layer](Transport_Layer_of_Internet_Protocol.md)), setting the
  destination port to 80 in the segment header.
- The [Internet Layer](Internet_Layer_of_Internet_Protocol.md) software on the
  client then wraps the TCP segment in an IP packet, which includes the
  destination IP address of the server in the packet header.
- At the [Link Layer](Link_Layer_of_Internet_Protocol.md) of the client device,
  the IP packet is encapsulated in a frame with the
  [MAC_address](MAC_addresses.md) of the local router in its header. The frame
  is wirelessly transmitted by the client device's WiFi hardware.
- The wireless access point receives the frame and passes to the router. The
  router examines the internet layer packet to determine the destination IP
  address.
- To reach the server, the request needs to travel through multiple routers on
  the internet and the process is replicated (looking up MAC address of the
  device and determining IP target). Eventually, the request reaches the router
  on the network where the server is connected.
- The last router puts the packet in a frame suitable for the server's local
  network and in the frame's header is the MAC address of the server.
- The server receives the frame and the packet is passed to the TCP/IP software
  stack. This passes the HTTP data to the process listening on TCP port 80.
- Web server software, listening on port 80 handles the request and replies to
  the client, start ing the process again in reverse order.


title: Insert_data_into_SQL_table
last_modified: 2024-10-18 18:55:56
body:
# Insert data into table with SQL `INSERT` statement

_A table named `sales`:_

| saleId | modelId | date       | salesPerson |
| ------ | ------- | ---------- | ----------- |
| 223    | 2       | 2020-01-09 | tgomay      |
| 321    | 3       | 2020-03-14 | snedgamon   |
| 491    | 4       | 2021-08-06 | tricksahoy  |

```sql
INSERT INTO sales
VALUES (1, 11, '2020-01-01','mhogan');
```

> If you intend to miss out a value, you shouldn't leave it blank, you should
> instead use `NULL` :

```sql
INSERT INTO sales
VALUES (1, 11, '2020-01-01', NULL);
```

> The approach above works well if the order of entry matches the order of the
> table fields. If this is not the case you can specify the order as part of the
> `INSERT` statement:

```sql
INSERT INTO sales**(employee_id, sale_id, model_id, sale_date)**
VALUES ('mhogan', 1, 11, '2020-01-01',);
```


title: Add_Subtract_Fractions
last_modified: 2024-10-18 18:55:56
body:
# Adding and subtracting fractions

## Adding/ subracting fractions with common denominators

For two fractions $\frac{a}{c}$ and $\frac{b}{c}$ with a common denominator,
their sum is defined as:

$$
    \frac{a}{c} + \frac{b}{c} = \frac{a + b}{c}
$$

For example:

$$
    \frac{2}{8} + \frac{3}{8} = \frac{5}{8}
$$

The same applies to subtraction:

$$
    \frac{a}{c} - \frac{b}{c} = \frac{a - b}{c}
$$

## Adding/ subracting fractions without common denominators

- Find the lowest common denominator for the two fractions
- Use this to create two equivalent fractions
- Add/subtract
- Reduce

### Lowest common denominator and lowest common multiple

Given the symmetry between
[factors and divisors](Factors_and_divisors.md) these
properties are related. Note however that the LCM is more generic: it applies to
any set of numbers not just fractions. Whereas the LCD is explicitly to do with
fractions (hence 'denominator').

- For two fractions $a, b$ (or a set), the LCD is the smallest number divisble
  by both the denominator of $a$ and the denominator of $b$ (or each member of
  the set).

- For two fractions $a, b$ (or a set), the LCM is the smallest number that is a
  multiple of the denominator of $a$ and the denominator of $b$ (or each member
  of the set).

In order to find the LCM of the set $\{12, 16\}$ we list the multiples of both:

$$
12, 24, 36, 48 \\
16, 32, 48
$$

Until we identify the smallest number common to both lists. In this case it
is 48. Thus the LCM of 12 and 16 is 48.

The relationship between LCM and LCD is that _the least common denominator is
the least common multiple of the fractions' denomintors_.

### Demonstration: addition

We can now use this to calculate the addition of two fractions without common
denominators: $\frac{4}{9} + \frac{1}{6}$.

First identify the common multiples of 9 and 6:

$$
9, 18, ... \\
6, 12, 18, ...
$$

The least common multiple is 18. We then think: what do we need to multiply each
denominator by to get 18?

In the case of the first fraction ($\frac{4}{9}$) it is 2:

$$
    \frac{4}{9 \cdot 2}  = \frac{4}{18}
$$

But what we do to the denominator, we must also do to the numerator, hence:

$$
    \frac{4 \cdot 2}{9 \cdot 2}  = \frac{8}{18}
$$

We then do the same to the second fraction ($\frac{1}{6}$). We need to multiply
its denominator by 3 to get 18 and we apply this also to the numerator.

$$
    \frac{1 \cdot 3}{6 \cdot 3}  = \frac{3}{18}
$$

We now have two fractions that share a common denominator so we can sum:

$$
    \frac{8}{18} + \frac{3}{18} = \frac{11}{18}
$$

### Demonstration: subtraction

Calculate:

$$
    \frac{3}{5} - \frac{2}{3}
$$

Once again we need to find the least common denominator for the two fractions.
We start by listing the common multiples for the two denominators 5 and 3:

$$
5, 10, 15, ... \\
3, 6, 9, 12, 15,...
$$

The lowest common multiple is 15. From the first fraction we get 15 by
multiplying by 3. With the second fraction we get 15 by multiplying by 5. Thus:

$$
    \frac{3 \cdot 3}{5 \cdot 3}  = \frac{9}{15}
$$

$$
    \frac{2 \cdot 5}{3 \cdot 5}  = \frac{10}{15}
$$

We can now carry out the subtraction:

$$
    \frac{9}{15}  -  \frac{10}{15} = -\frac{1}{15}
$$


title: Forms_in_React
last_modified: 2024-10-18 18:55:56
body:
# Forms using hooks

With hooks, form processing is exactly the same as
[classes](Forms_in_React.md) in terms of the overall
methodology, but the syntax is slightly different as a result of the `useState`
hook.

>

## Basic approach

Instead of using `this.state` and `this.setState` . We just have the `useState`
hook. But the controlled component principle is the same. Let's say we have a
simple email input:

```jsx
const [email, setEmail] = useState("");
```

As this is a form, the state change is going to be the result of user input. So
we need to prep our form to enable this.

```html
<input type="text" value="{email}" onChange="{setEmail}" />
```

Now we just need to make good on the `setEmail` method we declared when we
initialised the state:

```jsx
const handleChange = (event) => {
  setEmail(event.target.value);
};
```

### Applied example

Here is an applied example of the above approach for a form that has three input
fields. This component outputs the inputs as JSON on submit:

```jsx

function FormHook() {
  const [email, setEmail] = useState("");
  const [phone, setPhone] = useState("");
  const [age, setAge] = useState("");
  const [formOutput, setFormOutput] = useState("Form output");

  const handleSubmit = (event) => {
    event.preventDefault();
    setFormOutput(
      JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
    );
  };
	return (
		<form onSubmit={handleSubmit}>
			<input type="text" value={email} onChange={(event) => setEmail(event.target.value)}>
			<input type="text" value={phone} onChange={(event) => setPhone(event.target.value)}>
			<input type="number" value={age} onChange={(event) => setAge(event.target.value)}>
			<button type="submit">Submit</button>
		</form>
	)
};
```

## More complex forms

The above is fine if you only have one form with a couple of inputs. But if you
are managing multiple forms or forms with a complex array of inputs, you would
need to create `useState` declaration for every single input with a custom
`onChange` event for each one which is repetitious and not very clean.

So instead of this, just like with class-based controlled components, we use the
`name` HTML attribute to distinguish each input and create a generic `onChange`
function that distinguishes each separate input by destructuring a key, value
object using the `name`.

```jsx
<form onSubmit={handleSubmit}>
			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
			<button type="submit">Submit</button>
</form>
```

```jsx
const initialState = {
  email: "",
  phone: "",
  age: "",
};

const [formValues, setFormValues] = useState(initialState);

const handleChange = (event) => {
  const { name, value } = event.target;
  setFormValues({ ...formValues, [name]: value });
};
```

There are three parts:

1. First we create the initial state.
2. Next we store this initial state as the variable in the `useState`
   initialisation: `formValues` . We also provide a method `setFormValues` which
   will be used by the change handler to log the user's inputs.
3. Finally we create the function that will log the user changes. First we use
   object destructuring on the change event to enable us to retrieve the `name`
   and `value` attributes of the HTML inputs in the component. Then we use
   spread syntax to say that for each input pair, retrieve its value, using the
   destructured `name` variable as the key.

### Applied example

Below I have updated the previous context to this time reflect the new,
abstracted logic:

```jsx
function FormHookAbstracted() {
  const initialState = {
    email: "",
    phone: "",
    age: "",
  };
	const [formValues, setFormValues] = useState(initialState);
	const handleChange = (event) => {
    const { name, value } = event.target;
    setFormValues({ ...formValues, [name]: value });
  };
  const handleSubmit = (event) => {
    event.preventDefault();
    setFormOutput(
      JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
    );
  };
	return (
		<form onSubmit={handleSubmit}>
			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
			<button type="submit">Submit</button>
		</form>
	)
};
export default FormHookAbstracted;
```

Note that instead of individual variables `email` , `phone`, `age` , this
approach returns a single object `formValues` . We could therefore access the
individual values with e.g `[formValues.email](formvalues.email)` .

As it is an object, it makes resetting to the original state very easy, viz:

```jsx
const handleReset = () => {
  Object.values(formValues).map((x) => setFormValues(initialState));
};
```


title: Multiple_pointers
last_modified: 2024-10-18 18:55:56
body:
# Multiple pointers

The multiple pointers pattern can be useful for moving through an array and
comparing elements against each other in a time-efficient manner and without
costly multiple loops.

## Example: moving pairs

In this example we shuffle through an array creating a pair from each element
encountered. Thus for an array such as `[4, 3, 2, 1, 3, 6, 7]` we would return
`[ [ 4, 3 ], [ 3, 2 ], [ 2, 1 ], [ 1, 3 ], [ 3, 6 ], [ 6, 7 ] ]`.

```js
function movingPairs(arr) {
  const store = [];
  let left = 0;
  let right = 1;
  for (left; left < arr.length - right; left++) {
    store.push([arr[left], arr[right + left]]);
  }
  return store;
}
```

## Example: identify unique values

An example application of the above pattern would be identifying the number of
unique values in an array that contains duplicates. One way to do this in
JavaScript would be to use a Set however this is a more generic approach that
only requires a single loop:

```js
function uniqueValues(arr) {
  if (!arr.length) {
    return 0;
  } else {
    let count = 1;
    let left = 0;
    let right = 1;
    for (right; right < arr.length; right++) {
      if (arr[left] !== arr[right]) {
        count++;
      }
      left++;
    }

    return count;
  }
}
```

This works by having two pointers at either end of the array; one moving from
the right and one moving from the left. Whilst the right pointer is less than
the array length, the left pointer is incremented as the right moves closer to
it. At each incrementation, the values of pointers (used as indexes) are
compared for uniqueness, and a count is kept.

## Example: identify duplicates

This is very similar to the above but this time we are looking for duplicates
rather than unique values.

```js
function areThereDuplicatesPointer(...input) {
  let start = 0;
  let next = 1;
  while (next < input.length) {
    let same = input[start] === input[next];
    if (same) {
      return true;
    }
    start++;
    next++;
  }

  return false;
}
console.log(areThereDuplicatesPointer(1, 2, 3)); // false
console.log(areThereDuplicatesPointer(1, 2, 2)); // true
```


title: Deleting_Mongo_documents
last_modified: 2024-10-18 18:55:56
body:
# MongoDB: deleting a document from a collection

```js
async function deleteCourse(id) {
  const result = await Course.deleteOne({ id: id });
  console.log(result);
}
```

Use `findByIdAndRemove([id])` if you want to return the value that is deleted.

If we were to pass a query object that matches multiple documents in the
database to `deleteOne` it would only delete the first document returned. To
delete all use `deleteMany`.


title: Testing_with_Jest
last_modified: 2024-10-18 18:55:56
body:
# Testing with Jest

## Mocking classes/modules

### Classes

Let' say we have this class:

```js
// database.js
class Database {
  connect() {}
  save(data) {}
}
```

Then to mock:

```js
import Database from "./database";

// This will mock the whole Database class, replacing all methods with jest mock functions.
jest.mock("./database");

test("should use mocked save method", () => {
  const dbInstance = new Database();

  // Mocking the save method with a specific return value
  dbInstance.save.mockReturnValue(true);

  const result = dbInstance.save({ key: "value" });

  expect(result).toBe(true);
  expect(dbInstance.save).toHaveBeenCalledWith({ key: "value" });

  // The connect method is still a mock function (but without a specific behavior).
  dbInstance.connect();
  expect(dbInstance.connect).toHaveBeenCalled();
});
```

### Modules

Say we have the following module file:

```js
// utils.js
export const doSomething = () => {
  // ...
};

export const fetchUserData = async (userId) => {
  const response = await axios.get(`/api/users/${userId}`);
  return response.data;
};
```

Mocked:

```js
jest.mock("./utils", () => {
  return {
    doSomething: jest.fn(() => "mocked doSomething"),
    fetchUserData: jest.fn((userId) =>
      Promise.resolve({ id: userId, name: "Mock User" })
    ),
  };
});

test("should use mocked module functions", () => {
  expect(utils.doSomething()).toBe("mocked doSomething");
  expect(utils.doSomething).toHaveBeenCalled();

  const result = await utils.fetchUserData(123);

  expect(result).toEqual({ id: 123, name: "Mock User" });
  expect(utils.fetchUserData).toHaveBeenCalledWith(123);

});
```

### Inline mocking versus "per test" mocking

There are two different architectures that we can use when mocking modules and
classes: **inline** and **per test** mocking.

Here is the inline case:

```js
jest.mock("./some_module.js", () => {
  return {
    someFunction: jest.fn(() => "value"),
    someFunctionWithParam: jest.fn((param) => ({
      property: param,
    })),
    someAsyncFunction: jest.fn(() => Promise.resolve("value")),
  };
});
```

Here is the per test case:

```js
import { someModule } from "./some_module.js";

let someModuleMock;

someModuleMock = {
  someFunction: jest.fn(() => "value"),
  someFunctionWithParam: jest.fn((param) => ({
    property: param,
  })),
  someAsyncFunction: jest.fn(() => Promise.resolve("value")),
};

someModule.mockImplementation(() => someModuleMock);

it("should do something", () => {
  const newValue = "new value";
  someModule.someFunction.mockReturnValue(newValue);
});
```

The benefits of inline:

- Inline is good because everything is set up in one place
- Inline keeps consistency accross tests: every test case in the file will use
  the same mocked function unless overwritten within a test
- It lends itself to being a _global_ mock that can be used accross test files
  in a `__mocks__/` directory

The benefits of per-test:

- You can very mock implementations within the file, providing more granular
  control. You can redefine `someModuleMock` or parts of it
  (`someModule.someFunction`) throughout your test file to accomodate varied
  requirements between tests
- It’s beneficial when your tests have divergent requirements, as you can
  perform more detailed setups and overrides for each individual test case or
  suite, ensuring mocks are configured exactly as required.

#### Overriding inline mocks

Per test mocking makes it straightforward to change the test parameters of the
mocked module or class but you can also override inline mocks.

If we were using the `someModule` inline mock and we wanted to override the
`someFunction` function that we have defined inline, we would first import the
`someFunction` function and then use `mockImplementation` against it:

```js
import { someFunction } from "./some_module.js";
someFunction.mockImplementation(() => "custom value");
expect(someFunction()).toBe("custom value");

// Optional: Restore the original mock implementation after the test
someFunction.mockRestore();
```

Note: although we are importing `someFunction` we are not actually importing the
real function tha belongs to the module. Because Jest mocks all of its
properties and methods with the inline syntax, we are actually just importing
that which Jest has aready mocked, but the syntax is a bit misleading.

#### Applied to classes

The same approaches (with minor differences) can be used with classes:

Using inline (where the class is not the default export):

```js
jest.mock("./SomeClass", () => {
  return {
    SomeClass: jest.fn().mockImplementation(() => {
      return {
        someFunction: jest.fn(() => "value"),
        someFunctionWithParam: jest.fn((param) => ({ property: param })),
        someAsyncFunction: jest.fn(() => Promise.resolve("value")),
        someOtherFunctionThatResolves: jest.fn().mockResolvedValue("some data"),
      };
    }),
  };
});
```

Using per test:

```js
import SomeClass from "./someClass";

jest.mock("./someClass");

let someClassMock = {
  someFunction: jest.fn(() => "value"),
  someFunctionWithParam: jest.fn((param) => ({ property: param })),
  someAsyncFunction: jest.fn(() => Promise.resolve("value")),
};

// Mock class implementation
SomeClass.mockImplementation(() => someClassMock);

it("should do something", () => {
  const newValue = "new value";
  someClassMock.someFunction.mockReturnValue(newValue);
});
```

## Check that a function has been called within another function

```js
function toBeCalledFunction() {
  console.log("Original function called");
}

function callerFunction() {
  toBeCalledFunction();
}
```

```js
test("spy on toBeCalledFunction", () => {
  const spy = jest.spyOn(global, "toBeCalledFunction"); // Replace `global` with the appropriate object/context if the function is not global
  callerFunction();
  expect(spy).toHaveBeenCalled();
  spy.mockRestore(); // Restore the original function after spying
});
```

## Mock a function that needs to resolve to something within another function

We have two functions, one that gets data and another that processes it. We want
to mock the function that gets data and return a value that the processing
function can use.

```js
async function getData() {
  // ... Fetch some data from an API or database
  return fetchedData;
}

async function processData() {
  const data = await getData();
  // ... Process the data
  return processedData;
}
```

The mocking part:

```js
const mockData = { key: "value" }; // Mocked data

jest.mock("./path-to-file-where-getData-is", () => ({
  getData: jest.fn().mockResolvedValue(mockData),
}));

test("test processData function", async () => {
  const result = await processData();
  // Now, result contains the processed version of mockData
  expect(result).toEqual(/* expected processed data based on mockData */);
});
```

We could also combine the above with a spy to check that the `getData` function
was called:

```js
const getDataSpy = jest
  .spyOn(moduleContainingGetData, "getData")
  .mockResolvedValue(mockData);

const result = await processData();
expect(getDataSpy).toHaveBeenCalled();
expect(result).toEqual(/* expected processed data based on mockData */);
getDataSpy.mockRestore();
```

## Mock a function that takes arguments

```js
function addPrefix(str) {
  return `prefix-${str}`;
}
```

```js
test("dynamic mock for addPrefix function", () => {
  const mockFunction = jest.fn((str) => `mock-${str}`);

  // Example usage of mockFunction
  const result1 = mockFunction("test");
  const result2 = mockFunction("example");

  expect(result1).toBe("mock-test");
  expect(result2).toBe("mock-example");
});
```

## Mocking network requests

### Mocking Axios

```js
jest.mock("axios", () => ({
  get: jest.fn().mockResolvedValue(mockData),
  post: jest.fn().mockResolvedValue(mockData),
}));
```

Or we could implement this way:

```js
jest.mock("axios");
axios.get.mockResolvedValue({ data: "mockedData" });
axios.post.mockResolvedValue({ data: "mockedData" });
```

Then we can use the mocked axios functions in our tests:

```js
const result = await fetchData(); // the function that uses Axios `get``
expect(result).toBe("mockedGetData");

const result = await sendData({ key: "value" }); // the function tha uses Axios `post`
expect(result).toBe("mockedPostData");
```

### `mockImplementation`

For more configurable cases we can use `mockImplementation`:

```js
it("sends data", async () => {
  // Mock axios.post using mockImplementation
  axios.post.mockImplementation((url, data) => {
    if (data.key === "value") {
      return Promise.resolve({ data: "mockedPostData" });
    } else {
      return Promise.reject({ error: "An error occurred" });
    }
  });

  const result = await sendData({ key: "value" });

  expect(result).toBe("mockedPostData");
});
```

If we want to change the `get` and `post` values in different tests, we can do
so by using `mockImplementation`:

## Mocking exceptions

Again we use `mockImplementation`:

Say we have the following function:

```js
// fetchData.js
import axios from "axios";

const fetchData = async (url) => {
  try {
    const response = await axios.get(url);
    return response.data;
  } catch (error) {
    throw new Error("Error fetching data");
  }
};

export default fetchData;
```

We would mock the success and the error as follows:

```js
import axios from "axios";
import fetchData from "./fetchData";

jest.mock("axios");

describe("fetchData", () => {
  it("fetches data successfully", async () => {
    axios.get.mockResolvedValue({ data: "mockedData" });

    const result = await fetchData("https://api.example.com/data");

    expect(result).toBe("mockedData");
  });

  it("throws an error when fetching fails", async () => {
    axios.get.mockImplementation(() => {
      throw new Error("API error");
    });

    // We use an asynchronous assertion here because we're expecting a promise to reject
    await expect(fetchData("https://api.example.com/data")).rejects.toThrow(
      "Error fetching data"
    );
  });
});
```

## Parameterization

The following offers a good opportunity for parameterisation:

```js
it("should return page for deletion from `ipages-live`", async () => {
  // preview = false, isInternal = false
  await deletePageFromS3("url", false, false);
  const deleteObjectCommand = s3ClientMock.calls()[0].args[0];
  expect(deleteObjectCommand.input).toEqual({
    Bucket: "bbc-ise-ipages-live",
    Key: "url/index.html",
  });
});

it("should return page for deletion from `preview`", async () => {
  // preview = true, isInternal = false
  await deletePageFromS3("url", true, false);
  const deleteObjectCommand = s3ClientMock.calls()[0].args[0];
  expect(deleteObjectCommand.input).toEqual({
    Bucket: "staff.bbc.com-preview",
    Key: "preview/url/index.html",
  });
});

...
```

Each time we are passing in three parameters to the `deletePageFromS3` function
which is the object under test. Each time there are different variations in the
object that is output.

To parameterize the process rather than use repeated `it` blocks we can combine
the input paramters and outputs into an array:

```js
const testParams = [
  {
    preview: false,
    isInternal: false,
    bucket: "ipages-live",
    key: "url/index.html",
  },
  {
    preview: true,
    isInternal: false,
    bucket: "staff.com-preview",
    key: "preview/url/index.html",
  },
];
```

Then use `it.each` to loop through all possible parameter combinations:

```js
it.each(testParams)(
  "should return page for deletion from %s",
  async ({ preview, isInternal, bucket, key }) => {
    await deletePageFromS3("url", preview, isInternal);
    const deleteObjectCommand = s3ClientMock.calls()[0].args[0];
    expect(deleteObjectCommand.input).toEqual({
      Bucket: bucket,
      Key: key,
    });
  }
);
```

This uses the `%s` variable to print the parameters from each test, which
outputs:

```
  ✓ should return page for deletion from {
  preview: false,
  isInternal: false,
  bucket: 'ipages-live',
  key: 'url/index.html'
} (1 ms)
    ✓ should return page for deletion from {
  preview: true,
  isInternal: false,
  bucket: 'staff.com-preview',
  key: 'preview/url/index.html'
}
```


title: Map_and_filter_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Map and filter in Python

## Map

```py
data = [1, 3, 5, 2, 7, 4, 10]

new_data = map(lambda i: i + 10, data)
print(new_data)
```

We can also pass-in a function rather than use a lambda:

```py
def add_one(i):
    return i + 1

x = list(map(addOne, data))
# [2, 4, 6, 3, 8, 5, 11]
# necessary to add `list` to get some output
```

### Map returns an object

When you run `map` against a list it returns a map object not a list. This can
present problems if you are not aware of it since it is not an entity that you
can loop through.

The following map removes whitespaces from elements in a list:

```py
  lines = map(lambda x: x.strip(), lines)
```

In order to be able to run list-like operations against the resulting `lines`
object we would need to convert it to a list:

```py
  lines = list(map(lambda x: x.strip(), lines))
```

## Filter

```py
data = [1, 3, 5, 2, 7, 4, 10]

d1 = list(filter(lambda i: i % 2 == 0, data))
print(d1)
#  [2, 4, 10]

def is_even(i):
    return i % 2 == 0


# Filter for even numbers using a named function
d2 = list(filter(is_even, data))

# [2, 4, 10]
```

## Chaining

```py
data = [1, 3, 5, 2, 7, 4, 10]
new_data = list(map(lambda i: i + 10, filter(is_even, data)))
print(new_data)
# new_data: [12, 14, 20]
```


title: List_comprehension_in_Python
last_modified: 2024-10-18 18:55:56
body:
# List comprehension

List comprehension is a syntactic shorthand for applying a function to each
element in a list without explicitly using loop syntax.

Since its introduction to the language, the same functionality has become
achievable by using functional methods like
[`map` and `filter`](Map_and_filter_in_Python.md),
utilising [lambdas](Lambdas_in_Python.md)
however list comprehension is often more straightforward and easier to read.

## Syntax

Here is a basic example which applies `+ 1` to each integer in a list:

```python
values = [1, 2, 4, 6, 8, 9]

new_values = [i + 1 for i in values]
print('new_values', new_values)
# new_values [2, 3, 5, 7, 9, 10]
```

The basic syntax is as follows:

```
new_list  = [expression for each member in an iterable]
```

- The _expression_ can be the member itself, a call to a method, or any other
  valid expression that returns a value. In the example above, the expression
  `i + i` adds one to each member value.

- The _member_ is the object or value in the list or iterable. In the example
  above, the member value is _i_.

- The _iterable_ is a list, set, dictionary or any other object that can return
  its elements one at a time. In the example above, the iterable is each value
  in `values`.

This is a much more condensed way of achieving the same outcome with a
traditional loop:

```py
values = [1, 2, 4, 6, 8, 9]
new_list = []
for i in values:
  values.append(i+1)
```

### Another example

In the following example, we apply list comprehension with a `in range` loop
structure:

```py
new_list = [i * i for i in range(10) ]
print(new_list)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

```

### Adding a condition

We can apply a conditional to a comprehension:

```py
new_list = [item + 1 for item in values if item % 2 == 0]

print('new_list:', new_list)
# new_list: [3, 5, 7, 9]
```

### Filters

By applying a condition (and no execution to each element) we effectively create
a filter:

```py
numbers = [1, 2, 3, 4, 4, 4]
numbers_filtered = [i for i in numbers if i > 2]
print(numbers_filtered)
# [3, 4, 5]
```

For comparison, the same outcome could be achieved with a filter and lambda:

```py
with_filter = list(filter(lambda x: x > 2, numbers))
print(with_filter)
# [3, 4, 5]
```

## Set comprehension

We can also apply comprehension to sets. The syntax is practically identical but
the difference is the resultant data structure will not contain duplicates.

```py
numbers = [1, 2, 3, 4, 4, 4]
unique =  {i for i in numbers}
print(unique)
# {1,2,3,4}
```

## Dictionary comprehension

```py
squares = {i: i * i for i in range(5)}
print(squares)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
```


title: Ground
last_modified: 2024-10-18 18:55:56
body:
# Ground

The term 'ground' is used as a general reference for 'zero potential': the point
in an electrical circuit where there is no potential difference between the
positive and negative terminals of the voltage source.

As a consequence of the lack of potential, ground is a point at which no current
can be generated.

The term originates from domestic electrical systems where the circuit box is
literally attached to the ground (represented by the green and yellow ribboned
wires in plug sockets and light fixtures etc) where current is discharged to
prevent appliances emitting electrical shocks.

In circuit diagrams with simple DC current, ground is taken to be the negative
terminal of the voltage source.

The symbol for ground in circuit diagrams:

<img src="/home/thomas/repos/computer_science/img/ground-symbol.png" width="300px">


title: Further_examples_of_TS_generics
last_modified: 2024-10-18 18:55:56
body:
# Further examples of generics in TypeScript

## Basic function

In the code below we have a simple JavaScript function that receives a value and
an an array as parameters. It returns a new array comprising the original array
plus the additional value:

```js
function generateArray(existingArray, newValue) {
  return [...existingArray, newValue];
}
```

Imagine that we want to ensure that each of the parameters share the same data
type. In other words: if the function is passed a string array, the second
parameter must also be a string. For example, it should not be the case that you
can append a string to an array of numbers.

Now imagine that we don't know in advance what type the value or array will be,
we just know that the data types of the parameters must match.

In converting the function to TypeScript, one way of overcoming our lack of
foreknowledge would be to deploy `any`. This way it doesn't matter which types
are passed to the function:

```ts
function generateArray(existingArray: any[], newValue: any): any[] {
  return [...existingArray, newValue];
}
```

But this is no solution at all. The problem — as always with `any` — is that it
strips our function of any type checks whatsoever and would therefore invite
calls of form: `generateArray([1,2,3], 'lorem')`.

Enter generics:

```ts
function generateArray<T>(existingArr: T[], newValue: T): T[] {
  return [...existingArr, newValue];
}
```

Now, whilst we haven't asserted ahead of time which types will be used,
whichever types we do pass in, must match. The function header is saying:

- both arguments must be of the same type (represented by `T`)
- the function will return an array of this same `T` type.

If I then tried to run the function with unmatched types (for example
`generateArray([1,2,3,4], true)` ) TypeScript would raise the following error:

```
Argument of type 'boolean' is not assignable to parameter of type 'number'
```

Note that even though the function in question does not express any preference
for number types, given that our first parameter is a number, TypeScript knows
that the second parameter must also be a number.

> In the generic function we have used `T` as our placeholder for a generic type
> as this is the convention. However there is no compunction to do so. We could
> have used any letter or string, providing that the string is not a reserved
> term.

### More advanced function

This example demonstrates how we can use generics to reduce repetition when
writing functions and is also a more realistic use case.

Let's say we have two types or interfaces:

```tsx
type VideoFormatUrls = {
  format720p: URL;
  format1080p: URL;
};
```

```tsx
type SubtitleFormatUrls = {
  english: URL;
  german: URL;
};
```

An example of an object matching these type definitions:

```tsx
const videoFormats: VideoFormatUrls = {
	format720p: https://www.format720p.co.uk,
	format1080p: https://www.format1080p.co.uk
}
```

Imagine we wanted to be able to check whether a given film is available in a
certain video format. We could write a function like this:

```tsx
function isFormatAvailable(
  obj: VideoFormatUrls,
  format: string
): format is keyof VideoFormatUrls {
  return format in obj;
}
```

Now imagine that we need to do the same thing with subtitles, but given that
`isFormatAvailable()` is typed to the `VideoFormatUrls` type we would get an
error if we used this function for subtitles. But we also don't want to write a
near identical function typed to `SubtitleFormatUrls` to subtitles just to
ensure adequate type safety.

Alternatively we could use a union type, for example:

```tsx
function isFormatAvailable(
  obj: VideoFormatUrls | SubtitleFormatUrls,
  format: string
): format is keyof VideoFormatUrls {
  return format in obj;
}
```

But this quickly becomes unwieldy if we, for the sake of argument have a great
many URL types that we want the function to utilise.

This is where generics become super helpful. Here is how we would rewrite the
function as a generic:

```tsx
function isAvailable<Formats>(obj: Formats, key: string): key is keyof Formats {
  return key in obj;
}
```

We could then explicitly type our calls of this function, viz:

```tsx
isFormatAvailable<SubtitleFormatUrls>(subtitles, "english");
```


title: Lambda_triggers
last_modified: 2024-10-18 18:55:56
body:
# AWS Lambda triggers

Here are some common trigger patterns

### API Gateway trigger

- an HTTP request is sent to AWS API Gateway
- API Gateway triggers a Lambda function to execute

### DynamoDB table change trigger

- a record in a DynamoDB table is modified
- DynamoDB triggers a lambda function to execute

### S3 trigger

- a new file is created in S3
- S3 triggers a Lambda function to execute

### SQS trigger

- a new message is added to an [SQS](AWS_Messaging_services.md#sqs)
  queue
- SQS triggers a Lambda function to execute


title: ecec56e6_precursors_to_search_engines
last_modified: 2024-11-04 16:07:38
body:
# ecec56e6_precursors_to_search_engines

Before search engines as searchable indices of all content on the web, the
custom was for ISPs, browsers and websites (e.g. Yahoo!) to provide directories
of links to other sites. They functioned as sort of global web-portals.

![Yahoo's original homepage](../img/yahoo-original-homepage.png)

_The Yahoo! homepage from 1999._

![AltaVista homepage](../img/alta-vista.png)

_The AltaVista homepage from 1999. It has a primitive search engine but also
directories of sites._


title: Guide_to_YAML
last_modified: 2024-10-18 18:55:56
body:
# Guide to YAML

- Data description language
- Alternative to XML and JSON
- Easy to read by humans and process by code

## Main rule

> Never use tabs for indentation, use two spaces

## Available data types

- strings
- numbers
- booleans
- arrays
- maps (key, value pairs)

### Example

````yaml
# Basic scalar data types
age: 51
greeting: Hello, world
length: 182.3
happy: true
``

```yaml
# array
pets:
  - cat
  - dog

# nested array
pets:
  - cat
  - dog
    - staffy
    - pitty
````

```yaml
# map
languages:
  - java: advanced
  - python: average
  - javascript: basic
```

### Strings

- Don't have to use quotes unless string contains reserved YAML characters
  (dashes, colons etc)
- Can use single or double quotes

### Multi-line text

Two methods:

```yaml
# Literal block preserves new line characters
literal_block: |
  Lorem ipsum dolar sit avcc lorem dolar 
  Blah blah
  Blah
```

```yaml
folded_block: >
  Each different line will be folded back on itself so you don't have to keep
  scrolling to the right
```


title: Ports_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Ports

When working in development we are able to specify the specific port from which
we want top serve our application. In production, we do not always have this
control: the port will most likely be set by the provider of the server
environment.

While we may not know the specific port, whatever it is, it will be accessible
via the `PORT` environment variable. So we can use this when writing our
[event listeners](Events%20module.md#event-emitters):

```js
const port = process.env.PORT || 3000;
```

This way, if a port is set by the provider it will use it. If not, it will fall
back to 3000.


title: Python_data_types
last_modified: 2024-10-18 18:55:56
body:
# Python data-types

- Python is dynamically typed rather than untyped. It updates the types on the
  fly as you are writing your code.
- Type-hints in the editor like `-> str` mean "at the moment it is a string". It
  doesn't mean you can't redefine the value as something else.
- Each data type in Python inherits off of a built-in class, similar to
  prototypes in JS

The core data-types are as follows:

- [str](Strings_in_Python.md)
- bool
- float
- double

We can identify types using the built-in `type()` function:

```python
# Integer number
my_variable = 422
print(my_variable)
print(type(my_variable))
# <class 'int'>

# String type
my_variable = 'Natalia'
print(my_variable)
print(type(my_variable))
# <class 'str'>

# Boolean type
my_variable = True
print(my_variable)
print(type(my_variable))
# <class 'bool'>
```

## Converting data-types

For every data-type there is a corresponding converter method, e.g:

```python
a_string = '32'
print(f'a_string {a_string} is {type(a_string)}')
an_int = int(a_string)

print(f'an_int {a_string} is {type(an_int)}')
a_float = float(a_string)

print(f'a_float {a_string} is {type(a_float)}')
another_string = str(42)

print(f'another_string {a_string} is {type(another_string)}')
```


title: Bitwise_operators
last_modified: 2024-10-18 18:55:56
body:
# Bitwise operators

In addition to mathematical, logical and comparison operators, there are
_bitwise operators_. These operators execute conditions based on the actual bits
of a value rather than the values that the bits are encoded to represent.

Bitwise operators are typically represented with single characters of existing
operators, e.g. `&` instead of `&&`:

| Bitwise operation | Operator      |
| ----------------- | ------------- |
| AND               | `&`           |
| OR                | (single pipe) |
| NOT               | `~`           |

An example of using the `&` operator:

```py
x = 5
y = 3
a = x & y
b = x | y
```

The value of `a` will be 1. The reason is we are looking at the bit values of
`x` and `y` and then applying Boolean AND to each bit:

```
x = 5 = 0101
y = 3 = 0011
a = 1 = 0001
```

Working from right to left for each column:

- true and true = true
- false and true = false
- true and false = false
- false and false = false

This leaves us with 0001 which is equal to 1 in binary and denary.

For the case of bitwise OR we get 7 as the result of `x | y`:

```
x = 5 = 0101
y = 3 = 0011
b = 7 = 0111
```

- true or true = true
- false or true = true
- true or false = true
- false or false = true

This leaves us with 0111 which is equal to 7 in denary.

## Why use them?

Bitwise operations are more of a hallmark of lower-level programming. As bit
operations are the fastest and lowest level of computation, being able to
directly access and operate on bits within a programming language can be
beneficial when efficiency and speed of execution is a factor or when memory is
constrained.

## Related notes


title: Recording_and_playback_of_sound
last_modified: 2025-01-02 17:22:03
body:
# Recording and playback of sound

## Analogue

### Recording

The microphone converts sound waves into a continuous electrical signal.

The signal drives the recording equipment.

In the case of a vinyl recording: the signal drives a cutting head that carves a
groove into the master disk.

In the case of a tape recording: the signal drives electro-magnets that align
magnetic particles on the tape.

In both cases, **the recording medium physically mirrors the shape of the sound
wave**.

### Playback

In the case of vinyl, the needle follows the groove, moving up and down to
recreate the electrical signal.

In the case of tape, the magnetic patterns induce electrical current in the
playback head.

In each case, the signal is transferred directly to amplifiers and speakers.

## Digital

### Recording

Mostly covered in [Binary encoding of sound](Binary_encoding_of_sound.md).

An important point to note is that the binary encoding that results from the
sampling is lasered into the CD as microscopic impressions and depressions (pits
and lands)

### Playback

A laser in the reader reads the pits and lands and converts them back to binary
numbers. A DAC then converts the numbers back into a continuous electrical
signal which is then channelled to the amplifiers and speakers.

## From recording to production of storage medium

With analogue production recordings would be made onto tape. Multiple takes are
recorded, mixed and edited. This results in a master tape which is the final
version of the recorded sound.

This then goes to a mastering engineer for mastering which creates the master
mix. This consists in optimising the sound for the given format (vinyl or tape).
Also includes adjusting frequencies, levels and adding spacing between tracks.

Then the master disk enters production. A recording is made onto lacquer disc
which is very delicate. Often known as the "acetate". This is coated in metal to
create the "metal master", after various processes this goes to the pressing
plant who press vinyl copies from it.

Each stage can introduce subtle variations, especially with re-pressings.
Re-pressings require new stampers from the master which may have degraded in the
interim. Plus there is a limit to the amount of pressings possible with a given
stamper. The earlier pressings are therefore less degraded making them more
valuable.

## Degradation

With tape and vinyl each playback wears the medium, degrading the quality of the
captured signal. With CDs, there is no degradation and every copy is a perfect
copy of the original signal. However this capture, necessarily contains less
information than the analogue version because of sampling.


title: View_IP_addresses
last_modified: 2025-01-10 17:09:27
body:
# View IP addresses

Use `ip` package to view the [IP addresses](IP_addresses.md) associated with
your current host:

```sh
ip address show
```

I am curently using ethernet on the computer I am writing this. This is listed
as follows:

```
enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 90:2e:16:53:98:b9 brd ff:ff:ff:ff:ff:ffinet
192.168.0.3/24 brd 192.168.0.255 scope global dynamic noprefixroute enp0s31f6
    valid_lft 83353sec preferred_lft 83353sec
```

The most important line is the third. This indicates my IP address
(`192.168.0.3/24`) including its subnet mask.


title: Logical_indeterminacy
last_modified: 2024-10-18 18:55:56
body:
# Logical indeterminacy

The vast majority of propositions in natural and formal logical languages are
**neither
[logically true](Logical_truth_and_falsity.md#logical-truth)
or
[logically false](Logical_truth_and_falsity.md#logical-falsity)**.
This makes sense because propositions of this form are all either tautologies or
contradictions and as such do not express information about the state of events
in the world. We call propositions that are neither logically true or logically
false, **logically indeterminate** propositions.

## Informal definition

A proposition is logically indeterminate if it is neither logically true or
logically false. This is to say: it can be both [consistently](Consistency.md)
asserted and consistently denied.

For example the proposition:

```
It is raining.
```

May be true or false thus it can it both be asserted and denied quite
consistently. It is true if it actually is raining and false if it actually is
not raining. There is no logical contradiction implied by saying it is raining
when it isn't raining, this assertion is simply false. There is a contradiction
in saying that both states obtain. Thus the proposition:

```
It is raining and it is not raining.
```

Cannot be consistently asserted as there is no possibility of the proposition
being true. It is either raining or it isn't raining. Given the law for
conjunction, both conjuncts must be true for the proposition as a whole to be
true. But in the case of this proposition if one conjunct is true, the other
must be false and vice versa, hence it is not possible for the proposition to be
true at all. It can _only_ be false.

Contrariwise the proposition:

```
It is raining or it is not raining.
```

Cannot be consistently denied as there is no possibility of it being false. It
is either raining or not raining. Given the law for disjunction, either disjunct
can be true to make the proposition as a whole true. Given that it is either
raining or not raining in either scenario, the proposition as a whole will be
true. Therefore there is no possibility of it being false, it can _only_ be
true.

## Formal definition

> A proposition P is truth-functionally indeterminate if and only if it is
> neither truth-functionally true or truth-functionally false. should be avoided
> in arguments, they 'prove' everything whi

```
P
```

### Truth-table

| $P$ | $P$ |
| --- | --- |
| T   | T   |
| F   | F   |


title: Magnetic_tape
last_modified: 2024-10-18 18:55:56
body:
# Magnetic tape

Used for data storage in early digital computers (broadly from the
[UNIVAC](./The_History_of_Computing_Swade.md)) era until the mini-computer era.

While the UNIVAC was not the first to use magnetic tape, it popularised the
method due to its success and high profile.

![Magnetic tape reader in IBM computer](../img/magnetic-tape-ibm.jpeg)

It worked as follows. The tape was a long, narrow strip of plastic coated with a
magnetic material. Data is recorded on the the tape by magnetising tiny
particles on its surface. It was first used in the 1920s for audio recording.

Data is accessed in a linear, sequential manner. To reach a specific piece of
data, you often need to wind through all the preceding data

It was used for long term storage rather than RAM memory due to its sequential
nature. It stored data and program instructions that would be read into the
machine's memory. Data was also written out to magenetic tape, in order to store
and further process results.

It could store more data than punched cards and its sequential nature
accommodated batch processing well. However its sequential nature meant it was
slow at retreiving specific pieces of data as it would have to cycle through all
the values stored on the tape.

![Magnetic tape stored as casette](../img/magnetic-tape-disk.jpeg)

It developed from open-reel tapes to cartridges and cassettes. It was superseded
by hard disk drives and solid state drives.


title: Props_in_React
last_modified: 2024-10-18 18:55:56
body:
# Props

## Types or interfaces?

They are mostly interchangeable but there are some specific differences

### Interfaces

- Classes and other interfaces can extend an interface but not a type

  ```ts
  interface Animal {
    name: string;
  }

  interface Bear extends Animal {
    honey: boolean;
  }
  ```

- You can add properties to an interface without generating a double declaration
  error:

  ```ts
  interface Window {
      }

  interface Window {
    ts: TypeScriptAPI;
  }
  ```

### Types

You can create unions with types but not interfaces.

> The consensus seems to be that interfaces should be used over types unless
> there are ocassions when you do not want a type to be extendable /
> redeclarable. Or when you want to use unions.

## How we type props

The custom is to type props as an interface. This way we can easily type
function prop types.

```tsx
interface IProps {
  people: {
    name: string;
    age: number;
    note?: string;
  }[];
}

const List: React.FC<IProps> = ({people}: IProps) => {
    return()
}

// Note we say that the props into the func component are of type IProps
// And we destructure the people key

```

Then in the parent:

```tsx

const [people, setPeople] = useState<IState['people']>({});

<List props={people}>

```

## Common types for props

### Object with any number of properties

```tsx
interface IProps {
  obj: {};
}
```

### Array of objects

```tsx
interface IProps {
  val1: string;
  val2: boolean;
}
[];
```

### Functions

```tsx

// Function that doesn't receive or return anything
interface IProps {
    onClick: () => void;
}[]

// Function with named parameter
interface IProps {
    onClick: (id: number) => void;
}[]

// Function that takes an event
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
```

### Other React components

```js
interface IProps {
  children: React.ReactNode;
}

interface IProps {
  children: JSX.Element;
}
```

`React.ReactNode` covers everything that React can render. This should be
definitely used when the prop is a child component, otherwise `JSX.element` is
ok.

<p style="color: red;">Should I use type or interface? What is consensus?</p>


title: Instruction_set_architectures
last_modified: 2024-10-18 18:55:56
body:
# Instruction Set Architectures

## Summary

- Computers with different hardware execute machine code instructions (e.g
  _add_) in different ways. They have different _instruction set architectures_
  (ISAs).

- A family of CPUs that implement the core instructions of the
  [[Arithmetic_Logic_Unit]] in the same way share an ISA. Any software built for
  that ISA will work on any CPU that implements the ISA

- The two main CPU architectures are ARM and x86

## Architecture is logical not physical

The "architecture" of an ISA is logical rather than physical, i.e processors
that share an ISA may work very differently on the hardware level whilst still
adhering to the same instruction set.

## ARM and x86

The two main processor architectures are ARM and x86. x86 processors were first
introduced by Intel but are also made by AMD.

### x86

- First introduced by Intel but also made by AMD.

- Name stems from Intel's internal naming conventions - every new processor they
  introduced would have a letter designation ending with "86". Later they would
  adopt names such as "Pentium", "Celeron" etc. Regardless, these processors
  still fall under the "x86" family.

- Over time, new instructions have been added to the x86 architecture but they
  all maintain backwards compatibility with preceding generations.

- There have been different, successive generations of x86 corresponding to
  their [word-size](Signed_and_unsigned_numbers.md): 16-bit, 32-bit, 64-bit.
  Word size here just means how many bits the processor can work with at a time.
  A 34-bit processor can operate on values that are 32 bits in length. This
  means it has 32bit [[CPU_architecture#registers|registers]], a 32-bit data
  [[Bus|bus]], a 32-bit address bus and so on.

- AMD introduced the first 64-bit processor, not Intel but they later caught up.
  A 64-bit x86 processor is often referred to as _x64_ or _x86-64_.

### ARM

- x86 processors dominate the personal computer and server space

- On movile devices ARM ISA predominates

- The ARM company develops the architecture and standard which it licenses it to
  other companies to implement.

- Preferred on mobile because they have reduced power consumption and lower
  costs compared to x86.

- The processor is on a single chip that contains the CPU as well as memory and
  other hardware.


title: Variable_indirection_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Variable indirection

> Write proper notes on this

```sh
function array_empty() {
    declare -n arr=$1
    # Proceed if array not empty:
    if [ ${#arr[@]} -gt 0 ]; then
        return 1 # array is not empty
    else
        return 0 # array is empty
    fi
}

my_array=(1 2 3)

function push() {
    # $1 = stack name
    local stack_name="$1"
    if [ "${stack_name}" ]; then # stack exists
        if array_empty "${!stack_name}"; then
            echo "stack is empty"
        else
            echo "stack is not empty"
        fi
    else
        echo "Error: ${stack_name} does not exist."
    fi
}

push "my_array"

```

In Bash scripting, ${!stack_name} is an example of indirect variable referencing
or variable indirection. It's a way to use a variable whose name is stored in
another variable.

Let's break it down:

`${stack_name}`: This syntax is used to reference the value of a variable. So if
stack_name="my_array", then ${stack_name} would return "my_array".

`${!stack_name}`: Adding the ! introduces indirection. Now, instead of getting
the value of stack_name, you get the value of the variable whose name is stored
in stack_name. So if stack_name="my_array" and my_array=(1 2 3), then
${!stack_name} would return (1 2 3).

So, in the context of your script, `${!stack_name} allows you to pass the name
of an array (as a string) to your push function, and then use that string to
indirectly reference the actual array within the function.


title: systemd_status
last_modified: 2024-10-18 18:55:56
body:
# Get status of a specific unit

Here I have requested the status of the currently running `mongodb` unit:

```
$ systemctl status mongod
mongodb.service - MongoDB Database Server
     Loaded: loaded (/usr/lib/systemd/system/mongodb.service; enabled; preset: disabled)
     Active: active (running) since Wed 2022-08-17 07:25:27 BST; 24h ago
       Docs: https://docs.mongodb.org/manual
   Main PID: 931 (mongod)
     Memory: 304.1M
        CPU: 2min 18.630s
     CGroup: /system.slice/mongodb.service
             └─931 /usr/bin/mongod --config /etc/mongodb.conf
Aug 17 07:25:27 archbish systemd[1]: Started MongoDB Database Server.****
```

In addition to the core info it tells us the unit type. In this case it is a
service.

We can also view the journal entry for the given unit. This provides you with
its diagnostic log messages:

```
journalctl --unit=mongodb.service
- Boot b9565dfe8aca4d069143209b3aa84d8e --
Aug 05 18:31:30 archbish systemd[1]: Started MongoDB Database Server.
Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Deactivated successfully.
Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Consumed 3min 17.598s CPU time.
-- Boot 01922f84c3bd4b3a8f11824cf05f7320 --
Aug 07 11:58:09 archbish systemd[1]: Started MongoDB Database Server.
Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Deactivated successfully.
Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Consumed 5min 28.760s CPU time.
-- Boot e52b735e115c43bdad8c00462aaff395 --
Aug 10 13:13:22 archbish systemd[1]: Started MongoDB Database Server.
Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Deactivated successfully.
Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Consumed 2min 16.629s CPU time.
```

Each entry is organised around specific boots.


title: Non_null_assertion_in_TypeScript
last_modified: 2024-10-18 18:55:56
body:
# Non-null assertion

Oftentimes you will encounter errors of the form:

`Property [property_name] does not exist on type [type_name].ts(2339)`

This means the interpreter is not able to determine whether the property which
you are seeking to change exists. It can't be sure that you are not trying to
update a property that is either `null` or `undefined`. This is good type
checking but it means that in cases when _you know_ the property either exists
or _will_ exist at runtime, you are going to face a code-breaking error.

To get around this you can use non-null assertion. Like the name suggests, here
you are saying to TypeScript: thanks but I am sure this property exists. When
you do this you get the value you are trying to change with `null` and
`undefined` excluded from it.

This typically occurs when you are assigning a property to a value and TS
doesn't know whether the value will exist or be accessible at this point in the
runtime. A good scenario would be dynamic data passed into a function:

```ts
function doSomethingWith(typeAlias: ITypeAlias) {
  let x = typeAlias!.somePropertyEvidentAtRuntime;
}
```

However it should be used carefully and sparingly because you are obviously
turning off core type-checking and overuse nullifies the purpose of TypeScript.

One way to get around it is to use better
[type-guarding](Type_guarding_and_narrowing.md) and conditionality and to
cover cases where the value may be undefined.


title: Bauman_quote
last_modified: 2024-12-01 19:45:51
body:
# Bauman quote

_The yawning gap between the right of self-assertion and the capacity to control
the social settings which render such self-assertion feasible. It is from that
abysmal gap that the most poisonous effluvia contaminating the lives of
contemporary individuals emanate_.

Quoted in _The Age of Surveillance Capitalism_ (2019): 45


title: Time_and_computers
last_modified: 2024-10-18 18:55:56
body:
# Time and computers

## Epochs and Unix Time

An epoch is a period of time identified by a starting point.

The standard epoch for measuring against is known colloqially as "Unix Time":
midnight on 1st January 1970. Unix time is the number of seconds that have
elapsed since this point. This is the standard for Windows and most unix
systems.

For example midnight on 2nd January 1970 would be 86400 seconds since the epoch.
The deduction is as follows:

```
60 * 60 * 24 = 86400
```

We are multiplpying the number of seconds in a minute by the number of minutes
in an hour by the number of hours in a day.

To represent times and dates before 1970, we use negative integers.

## UTC and time zones

"Coordinated Universal Time" (UTC) is the time standard against which the
world's timekeeping is synchronized. It is not itself a timezone, it is a
transcendent standard that defines what time zones are.

Time zones are defined relative to UTC, by their offset to this value.

For example North America is behind UTC by five or six hours hence uses the
notation UTC-5:00 or UTC-6:00.

UTC is the successor to GMT of which there were variances necessitating a
universal value. Despite this GMT is equal to UTC+00:00 so apart from when
daylight saving is in effect in the UK, GMT = UTC.

Depending on your locale, relative to UTC, you will get different outputs when
you attempt to log Unix Time.

Also daylight savings can impact on the outputs. For instance for half of the
year, when DST applies, the UK is UTC+01:00.

## Examples in Python

The following gives us the unix seconds in my current time zone (GMT DST):

```py
import time
print(time.time())
# 1714322393.2929392
```

If I want UTC, I can do:

```py
import datetime
print(datetime.datetime.utcnow().strftime('%s'))
# '1714318952'
```

We see clearly that they are not identical.


title: Creating_a_RESTful_API_POST
last_modified: 2024-10-18 18:55:56
body:
# Creating a RESTful API: `POST` requests

To demonstrate the handling of POST requests, we will create a handler that add
a new element to the array of courses.

```js
router.post("/", (req, res) => {
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});
```

Here we use the body that is sent from the client and isolate the field `name`.
This presupposes that the client is sending us data with the following shape as
the body:

```json
{
  "name": "Biology and Life Sciences"
}
```

To execute the PUT request from the frontend:

```js
const addCourse = async (newCourse) => {
  try {
    const resp = await axios.post("http://localhost:3000/api/courses", {
      name: newCourse,
    });
    console.log(resp.data);
  } catch (err) {
    console.error(err);
  }
};
addCourse("Biology and Life Sciences");
```

Which returns:

```js
{ id: 4, name: 'Biology and Life Sciences' }
```

The `id` is added by the server, not the client. Having created the new value we
add it to our `courses` array. (In reality we would be creating a new entry in a
database.) Then we follow the convention of returning the new value back to the
client.

## Validation

We should accept alterations to the database that are not first validated. We
can use the
[Joi validator](Validation_in_NodeJS.md) to vet
the request:

```js
function validateCourse(course) {
  const schema = Joi.object({
    name: Joi.string().min(3).required(),
  });

  const { error } = schema.validate(course);
  return error;
}
```

We can then add the validation as part of our general error handling:

```js
router.post("/", (req, res) => {
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  const { error } = schema.validate(req.body);
  if (error)
    return error.details.map((joiErr) => res.status(400).send(joiErr.message));

  courses.push(course);
  res.send(course);
});
```


title: Handle_multiple_endpoints_single_lambda
last_modified: 2024-10-18 18:55:56
body:
# Handle multiple API Gateway endpoints in a single lambda

With the following config we have a single lambda (`/query-waktime`) with
multiple endpoints:

```yml
Resources:
  QueryWakatimeFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/query-wakatime/
      Handler: index.handler
      Events:
        MainMetrics:
          Type: Api
          Properties:
            Path: /query-wakatime/main-metrics
            Method: get
            Auth:
              Authorizer: AWS_IAM
        Durations:
          Type: Api
          Properties:
            Path: /query-wakatime/durations
            Method: get
            Auth:
              Authorizer: AWS_IAM
        TodayOnly:
          Type: Api
          Properties:
            Path: /query-wakatime/today-only
            Method: get
            Auth:
              Authorizer: AWS_IAM
```

Our endpoints are as follows:

- `/query-wakatime/main-metrics`
- `/query-wakatime/durations`
- `/query-wakatime/today-only`

Each returns a different dataset from an external API. The lambda function makes
a different request to the API based on the endpoint it receives and the time
period that is passed as a query string parameter, e.g.
`/query-wakatime?range=last_7_days`.

Below is a template for concisely handling requests to the different endpoints
in the single lambda function wihout excessive repetition.

```js
const getEndpoint = (path: string, timePeriod?: string | undefined) => {
  const basePath = "/users/current";
  switch (path) {
    case "/query-wakatime/main-metrics":
      return `${basePath}/stats/${timePeriod}`;
    case "/query-wakatime/durations":
      return `${basePath}/summaries?range=${timePeriod}`;
    case "/query-wakatime/today-only":
      return `${basePath}/status_bar/today`;
  }
};

export const handler = async (event) => {
  const fetchClient = new FetchClient("https://wakatime.com/api/v1/");
  const path = event.path;
  const timePeriod = event.queryStringParameters?.timePeriod;
  const endpoint = getEndpoint(path, timePeriod);

  const init: RequestInit = {
    headers: {
      Authorization: `Basic ${encodedApiKey}`,
    },
  };

  if (!endpoint) {
    throw new Error("Endpoint is undefined")
  }

 let data = await fetchClient.get(endpoint, init)
 let dataJson = (await data.json()) as string

 response = {
    statusCode: 200,
    body: JSON.stringify(dataJson),
    headers: responseHeaders,
    }
};



```


title: Lists_and_arrays_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Arrays in Bash

We define an array as follows:

```bash
words=(here are some words)
```

We can also explicitly define an array using `declare` :

```bash
declare -a words=("element1" "element2" "element3")
```

## Index notation

We access specific array elements by their index using the same braces style we
use with variables:

```bash
echo "${words[2]}"

# element3
```

## Iterating through arrays

```bash
for i in "${words[@]}"
do
   echo "$i"
   # or do whatever with individual element of the array
done
# element1 element2 element3
```

Note that `@` here is a special symbol standing for all the members of the
`words` array.

## Sorting arrays

### Sorting an integer array highests to lowest

```bash
sorted_array=($(echo "${array[@]}" | tr " " "\n" | sort -nr))
```

Where `array` is the name of the original array. The sorted array will be stored
in the `sorted_array` array.

The `sort` command sorts the input in reverse numerical order (`-n` for
numerical sort and `-r` for reverse sort). The `tr` command is used to convert
the spaces in the array to newline characters so that each element is sorted on
a separate line.

## Pushing, appending to an array

We use the `+=` shorthand to add elements to a preexisting array:

```bash
preExistingArray=(1 2 3)
preExistingArray+=(4)
echo preExistingArray
# 1 2 3 4

```

> Note that we have to put the item we want to addend within array brackets

## Check if array empty

```sh
an_array=()

if [ -z "${another_array[@]}" ]; then
    echo "Array is empty"
else
    echo "Array is not empty"
fi
```

Here we pass all the elements of the array to a
[test](Test_values_in_Bash.md) condition which
tests for an empty string.

> NB: This will not immediately work in the context of a function. See below.

## Weirdness with functions

When you pass an array as an argument to a
[function](Functions_in_Bash.md) it will not
immediately be understood to be an array.

When we use `$1` to individuate the first function argument this is read as
string. So if you parsed an array argument as `$1`, any logic you have in the
function will work on the assumption that the argument is a string, not an
array.

To get round this we have to effectively _redeclare_ the argument as an array
before running any array logic. We do this through a **nameref** (a reference to
a variable). The nameref resolves to the value of the variable it references.
This allows you to indirectly manipulate the value of the original variable
through the nameref.

A nameref is created with the `-n` flag. The following function uses this method
to check if an array is empty:

```sh
function array_empty() {
    declare -n arr=$1
    if [ ${#arr[@]} -gt 0 ]; then
        echo "array is not empty"
    else
        echo "array is empty"
    fi
}

my_array=()
array_empty "my_array"
```

You'll notice when we invoke the function we pass the array as a string, this
facilitates the nameref operation in the function.

## Associational arrays / maps

With Bash 4 we gained an additional array-like data structure that is key-value
based and similar to maps in other languages.

```bash
declare -A rock=(["win"]="scissors" ["lose"]="paper")
```

We would then individuate a value with `"${rock[win]}"`

## Lists as implicit string arrays

When we use the term **list** in bash, we are not actually referring to a
specific type of data structure. Instead a **list variable** is really just a
normal variable wrapped in quote marks that has strings separated by spaces.
Despite the fact that this is not an actual iterative data structure, we are
still able to loop through variables of this type.

```bash
A_STR_LIST="cat dog hamster"
AN_INT_LIST="1 2 3"
```

To iterate through a list variable, we can use a for loop:

```bash
for ele in $A_STR_LIST; do
    echo $ele
done
```

We are leveraging this aspect of Bash when we
[loop through each character in a string](Strings_in_Bash.md#loop-through-each-character-in-a-string).


title: Binary_addition
last_modified: 2024-10-18 18:55:56
body:
# Binary addition

- We add binary values in columns just like we would with denary addition.
- Each column is classified on the basis of place-value. In denary this is 10,
  in binary it is 2.
- When we conduct a binary addition, we add the binary values as if they were
  normal integers but we represent the sums as binary.
  - For example: $1 + 1 = 2$ for the calculation but the sum is $10$

## Examples

### Example one

$$
1010 + 0111 = 10001
$$

$$
10 + 7 = 17
$$

In the first column: $1 + 0 = 1$, so we simply put the binary value for $1$:

```
1010
0111
____
   1
```

In the second column: $1 + 1 = 2$. In binary this is represented as $10$. So we
put $0$ beneath the bar and carry the $1$:

```
 1
1010
0111
____
  01
```

In the third column, we repeat the previous process. We are presented with
$1 + 0 + 1$ which is $2$. As $2$ is $10$ in binary, we put the zero beneath the
line and carry the $1$:

```
11
1010
0111
____
 001
```

In the final column, we again have $1+1$ giving us $2$ or $10$ but at this point
we cannot carry any more because we have reached the final column. So instead of
carrying the $1$ we just put both digits beneath the line $10$.

```
 11
 1010
 0111
_____
10001
```

### Example two

$$
1001 + 0111 = 10000
$$

$$
9 + 7 = 16
$$

```
 111
 1001
 0111
_____
10000
```


title: Redirection_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Redirection

## Redirecting outputs

The symbol `>` is called the **redirection operator** because it redirects
`stdout` to another program or file. You most frequently use this when you want
to save contents to a file rather than standard output.

```bash
ls | grep d* > result.txt
```

### Combining redirection with file escriptors

It is common practice to combine redirection with the
[file descriptors](File_descriptors.md) to redirect
the output of `stdout` and `stderr`. A common case is to
[redirect error output to `/dev/null`](Redirect_to_dev_null.md).

Redirection defaults to interpreting `>` as the redirection of `stdout` (`1`);

## Redirecting inputs

We can also switch the direction of the redirection symbol and pass in a file to
a command rather than command ouput to a file:

```bash
sql-processing-program < data.sql
```

We can redirect a string with three carets:

```bash
program <<< "this is a string input"
```

## Appending

We use `>>` to append contents on the next available line of a pre-existing
file. Continuing on from the example above:

```bash
echo 'These are the files I just grepped' >> result.txt
```


title: Multiplicative_property_of_negative_one
last_modified: 2024-10-18 18:55:56
body:
# The Multiplicative Property of Negative One

> **Let $a$ represent any member of $\mathbb{Z}$, then:**

$$ (-1) \cdot a = -a $$


title: Binary_encoding_of_text
last_modified: 2024-11-04 14:22:11
body:
# Binary encoding of text

Text encoding is an applied instance of [binary encoding](Binary_encoding.md).

## ASCII

There are around 100 characters in total required to render A-Z, a-z, 0-9 and
the special characters of Lating text. The ASCII (American Standard Code for
Information Interchange) system achieves this with 8-bit code. Thus, each
character symbol corresponds to a byte. As $2^8 = 256$, this allows for a total
of 256 characters (where only 7-bits are sufficient, a leading `0` is added).

Below are some examples of the ASCII correspondences:

| Binary    | Hex | Character |
| --------- | --- | --------- |
| 00100000  | 20  | [space]   |
| 00100001  | 21  | !         |
| 001010112 | 2B  | +         |

However there are only 128 characters represented in ASCII, thus using 256-bits
is somewhat excessive. This lead people to try and use the remaining, free 128
bits to accommodate characters from non-English languages. This was quickly
found to be insufficient, necessitating the development of a new encoding
standard, Unicode...

## Unicode and UTF-8

Whereas ASCII only encodes 128 English alphanumeric characters, the scope of
Unicode is much broader, as such it is a superset of ASCII (every character in
ASCII is in Unicode but not the converse). Unicode is a universal character
encoding that defines every character in every spoken language of the world. The
Unicode standard is maintained by the Unicode Consortium and defines more than
1,40,000 characters from more than 150 modern and historic scripts along with
emoji.

In contrast to ASCII, it doesn't achieve this by mapping every character to a
bit. Instead it provides an abstract representation of every character which is
then encoded using a designated encoding protocol, such as UTF-8, UTF-16, UTF-32
etc. These abstract representations are called "code-points" and are represented
as hexadecimal numbers between 0xO - 0x10FFFF (1114111), prepended by `U+`, for
example ` U+00F7` which is the sign for division.

As the encoding names suggest they encode to different bit sizes:

- UTF-8 and UTF-16 are variable length encodings.
- In UTF-8, a character may occupy a minimum of 8 bits.
- In UTF-16, a character length starts with 16 bits.
- UTF-32 is a fixed length encoding of 32 bits.

> Unicode can be stored using several different encodings, which translate the
> character codes into sequences of bytes. So, crucially Unicode is not itself
> an encoding.

UTF-8 uses the ASCII set for the first 128 characters. That's handy because it
means ASCII text is also valid in UTF-8.


title: Arithmetic_Logic_Unit
last_modified: 2024-10-18 18:55:56
body:
# Arithmetic Logic Unit (ALU)

The ALU is the centerpiece or core of the
[CPU](CPU_architecture.md) architecture, where the
binary calculations occur. All the other components on the CPU chip are
appendanges to the execution that occurs within the ALU.

The ALU comprises
[logic gates](Logic_gates.md) that
execute the instructions passed from memory and where the data stored by the
registers is acted upon. A processor's ALU is just a complex combinatorial logic
circuit.

It executes arithmetic and logical operations on binary numbers and where you
will find operations conducted by
[full-adders and half adders](Half_adder_and_full_adder.md)
etc.

More specifically, the ALU is responsible for the _execute_ phase of the
[fetch, decode, execute cycle](Fetch_decode_execute.md).

## ALU execution lifecycle

1. **Inputs**: The ALU receives two operands and a control signal as inputs. The
   operands are the data on which the operations will be performed. The control
   signal tells the ALU which operation it needs to perform.
2. **Perform operation**: The ALU carries out the requested operation. For
   instance, if the control signal indicates an addition operation, the ALU sums
   the two operands.
3. **Output**: The ALU then sends the operation to another part of the CPU for
   further processing or storage. The ALU also outputs a status bit that can be
   used by other parts of the CPU to make decisions. For instance if the additon
   results in a value that is too large to be stored, the ALU will set an
   overflow flag.


title: Recursion
last_modified: 2024-10-18 18:55:56
body:
> A recursive function is a function that calls itself in its definition.

More generally recursion means when a thing is defined in terms of itself. There
are visual analogues that help to represent the idea such as the Droste effect
where an image contains a version of itself within itself. The ouroboros is
another example. Also fractals display recursive properties.

## Schema

The general structure of a recursive function is as follows:
![javascript-recursion.png](javascript-recursion.png)

## Why use recursive functions?

Recursion is made for solving problems that can be broken down into smaller,
repetitive problems. It is especially good for working on things that have many
possible branches but are too complex for an iterative approach or too costly in
terms of memory and time complexity.

Recursive programming differs from **iterative** programming but both have
similar use cases. Looping is a canonical example of working iteratively.

## Base condition

> Once a condition is met, the function stops calling itself. This is called a
> base condition.

Because recursion has the potential for infinity, to use it, we must specify a
point at which it ends. However as we are not using an iterative approach we
cannot rely on `while` or `foreach` to specify the boundaries of its operation.
We call this the **base condition** and this will typically be specified using
conditional logic.

The schema for a recursive function with a base condition is:

```jsx
function recurse() {
  if (condition) {
    recurse();
  } else {
    // stop calling recurse()
  }
}

recurse();
```

## Demonstrations

### Countdown

```jsx
// program to count down numbers to 1
function countDown(number) {
  // display the number
  console.log(number);

  // decrease the number value
  let newNumber = number - 1;

  // base case
  if (newNumber > 0) {
    countDown(newNumber);
  }
}

countDown(4);
```

- This code takes `4` as it's input and then outputs a countdown returning:
  `4, 3, 2, 1`
- In each iteration, the number value is decreased by 1
- The base condition is `newNumber > 0` . This breaks the recursive loop once
  the output reaches `1` and stops it continuing into negative integers.

Each stage in the process is noted below:

```
countDown(4) prints 4 and calls countDown(3)
countDown(3) prints 3 and calls countDown(2)
countDown(2) prints 2 and calls countDown(1)
countDown(1) prints 1 and calls countDown(0)
```

### Finding factorials

> The factorial of a positive integer **n** is the product of all the positive
> integers less than or equal to **n**.

To arrive at the factorial of **n** you subtract 1 from **n** and multiply the
result of the subtraction by **n**. You repeat until the subtractive process
runs out of positive integers. For example, if 4 is **n,** the factorial of
**n** is **24:**

$$ 4 _ 3 _ 2 \*1 $$

4 multiplied by 3 gives you 12, 12 multiplied by 2 gives you 24. 24 multiplied
by 1 is 24.

This is clearly a process that could be implemented with a recursive function:

```js
// program to find the factorial of a number
function factorial(x) {
  // if number is 0
  if (x === 0) {
    return 1;
  }

  // if number is positive
  else {
    return x * factorial(x - 1);
  }
}

let num = 3;

// calling factorial() if num is non-negative
if (num > 0) {
  let result = factorial(num);
  console.log(`The factorial of ${num} is ${result}`);
}
```

![javascript-factorial 1.png](javascript-factorial%201.png)


title: Joins_in_SQL
last_modified: 2024-10-18 18:55:56
body:
# Joins in SQL

<!-- Once a relationship has been created using primary and foreign keys (as detailed in the previous section), you are able to combine and integrate data from the different tables. This is known as performing **joins.** -->

We perform joins in SQL when we combine and integrate data from multiple tables.
In order for a join to be possible, **the tables you want to join must have rows
that share the same fields**.

The output will be represented as a table but it is virtual, not an actual
table. (If you wish to actually create a table or a view off the back of a join
operation you should combine the join with the
[`CREATE TABLE`](Create_an_SQL_table.md) command etc.)

## Inner joins

> An inner join combines rows that have matching values in two or more tables.
> This join is based on the existence of a common field between the tables and
> is used to retrieve data that appears in both tables.

The following is a good scenario for creating an inner join:

> We want to create a list of the name of all computers that have been sold and
> when they were sold.

We will be working from the following tables.

_The `sales` table_:

| saleId | modelId | saleDate   | employeeId | price   |
| ------ | ------- | ---------- | ---------- | ------- |
| 1      | 44      | 2020-07-27 | tbishop    | 40.99   |
| 2      | 22      | 2021-02-05 | tbishop    | 986.99  |
| 3      | 14      | 2022-11-16 | tgnomay    | 1248.99 |

_The `model` table_:

| modelId | modelName            |
| ------- | -------------------- |
| 44      | Raspberry Pi Model A |
| 22      | Apple MacBook Air    |
| 14      | Lenovo ThinkPad P15  |

The data points we need are not provided in a single table. `sales` gives us the
`saleDate` but not the `modelName`. In order to meet our requirements we must
perform a join that combines `modelName` from the `model` table and `saleDate`
from the `sale` table to give us a table like the following:

| modelName            | sale_date  |
| -------------------- | ---------- |
| Raspberry Pi Model A | 2015-02-01 |
| Apple Macbook Air    | 2018-11-01 |
| Lenovo ThinkPad P15  | 2018-11-01 |

We can do this by utilising the field they have in common: `modelId`.

### Implementation

The general syntax for creating an inner join from two tables that share a
common field is as follows:

```sql
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.columnName = table2.columnName
```

So basically, look at `table1` and `table2` return the rows where the fields for
`table1` and `table2` match, where these fields are the ones specified in the
`SELECT`.

Applied to our example:

```sql
SELECT model.modelName, sales.saleDate -- Name the fields
FROM model -- Specify the first table
INNER JOIN sales -- Specify the second table
ON model.model_id = sales.model_id; -- Specify the match criteria
```

> It is important to note that the match must _be_ a match. Both tables must
> have a row with the same value for `modelId` for the join to be applied. If
> there is a `modelId` of X in `sales` but no corresponding X for `modelId` in
> `model`, nothing will be returned for that row.

We can represent the logical relationship that obtains between the `sales` and
`model` tables as follows:

![](/img/sql-inner-join.png)

## Outer joins

Outer joins are joins that return matched values **and unmatched** values from
either or both tables.

To explain outer joins we need to expand our data set:

_The `sales` table_:

| saleId | modelId | saleDate   | employeeId | price   |
| ------ | ------- | ---------- | ---------- | ------- |
| 1      | 44      | 2020-07-27 | tbishop    | 40.99   |
| 2      | 22      | 2021-02-05 | tbishop    | 986.99  |
| 3      | 14      | 2022-11-16 | tgnomay    | 1248.99 |
| 4      |         | 2020-03-01 | msmelk     | 699.99  |

_The `model` table_:

| modelId | modelName            |
| ------- | -------------------- |
| 44      | Raspberry Pi Model A |
| 22      | Apple MacBook Air    |
| 14      | Lenovo ThinkPad P15  |
| 66      | Google Chromebook    |

> We will assume that `sales` is our left table and `model` our right.

### Left outer join

A left outer join returns all records from the left or first table and the
matching records from the right or second table. If there are not matches on the
right then only the left data is returned.

In the context of our dataset, in the _sales_ database we have a row where there
is a sale with no corresponding `modelId`. If we performed a left outer join
this would give us the following table in return:

| modelName            | sale_date  |
| -------------------- | ---------- |
| Raspberry Pi Model A | 2015-02-01 |
| Apple Macbook Air    | 2018-11-01 |
| Lenovo ThinkPad P15  | 2018-11-01 |
|                      | 2020-03-01 |

The logical relationship sustained between `sales` and `model` by a left inner
join is represented in the following diagram:

![](/img/sql-left-outer-join.png)

#### Implementation

The schematic form:

```sql
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name;
```

Applied to our data set:

```sql
SELECT model.modelName, sales.saleDate
FROM sales.saleDate
LEFT JOIN model
ON sales.modelId = model.modelId
```

### Right outer join

This is the inverse of the right outer join. A right outer join returns all
records from the right or second table and the matching records from the left or
first table. If there are not matches on the left then only the right data is
returned.

In the context of our dataset, in the _model_ database we have a row where there
is a `modelId` without a corresponding entry in the `sales` table. If we
performed a right outer join this would give us the following table in return:

| modelName            | sale_date  |
| -------------------- | ---------- |
| Raspberry Pi Model A | 2015-02-01 |
| Apple Macbook Air    | 2018-11-01 |
| Lenovo ThinkPad P15  | 2018-11-01 |
| Google Chromebook    |            |

The logical relationship sustained between `sales` and `model` by a right inner
join is represented in the following diagram:

![](/img/sql-right-outer-join.png)

#### Implementation

The schematic form:

```sql
SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name = table2.column_name;
```

Applied to our data set:

```sql
SELECT model.modelName, sales.saleDate
FROM sales.saleDate
RIGHT JOIN model
ON sales.modelId = model.modelId
```

### Full outer join

The full outer join returns all rows when there is a match in either the left or
the right table. So, for table A and table B the full join returns all rows in A
and all rows in B including those where there is a match between A and B. This
is the broadest type of join and can often result in large data sets.

In the context of our dataset it would result in the following table being
generated:

| modelName            | sale_date  |
| -------------------- | ---------- |
| Raspberry Pi Model A | 2015-02-01 |
| Apple Macbook Air    | 2018-11-01 |
| Lenovo ThinkPad P15  | 2018-11-01 |
|                      | 2020-03-01 |
| Google Chromebook    |            |

Represented by the following diagram:

![](/img/sql-full-outer-join.png)

#### Implementation

The schematic form:

```sql
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name = table2.column_name;
```

Applied to our data set:

```sql
SELECT model.modelName, sales.saleDate
FROM sales.saleDate
FULL OUTER JOIN model
ON sales.modelId = model.modelId
```

This type of join is used when you want to discern when there is _not_ a match
between two fields across tables. For example: imagine that you wanted a list of
computers that had never been sold. In this case, you would be interested in
rows where there is a `model_id` without a corresponding `sales_id` .

In SQL this would be achieved with:

```sql
SELECT model.name, sales.sale_date
FROM model
LEFT JOIN sales on model.model_id = sales.model_id;
```

Note that this would return all the model names but where there isn't a sale
data, `NULL` would be returned. This is an **important distinction :** the outer
join method doesn't just return the rows with a `NULL` value for `sale_date` as
we might expect. It returns all models along with those that have not been sold.
This is because it is oriented to the "left" table, equivalent to the table in
the SQL that we cited first with the `on` keyword.

> A left outer join returns all the records from the left (model) table and
> those that match in the right (sales) table. Where there are no matching
> records in the right (sales) table, a `NULL` value is returned.

A **right outer join**, often referred to as a right join, is the opposite of a
left outer; it returns all the records from the right table and those that match
in the left table. In our scenario this would be all the models that had a
`sale_date` including models that didn't have a `sale_date` , i.e which returned
`NULL`

Finally, a **full outer join** returns all the records from both tables, and
where a record cannot be matched, a NULL value is returned. So this would mean
there could be `NULL`s in both fields of the returned rows.

We can combine multiple types of join in the same SQL query:

```sql
SELECT model.name, sales.sale_date, manufacturer.url
FROM model
LEFT JOIN sales on model.model_id = sales.model_id
INNER JOIN manufacturer on model.manufacturer_id = manufacturer.manufacturer_id;
```


title: Law_of_the_Excluded_Middle
last_modified: 2024-10-18 18:55:56
body:
# Law of the Excluded Middle

> Every proposition has to be either true or false. There can be no middle
> ground.

$$
P \lor \sim P
$$


title: Order_of_operations
last_modified: 2024-10-18 19:18:57
body:
# Order of operations

1. Evaluate expressions in **parentheses**
1. Evaluate **exponents**
1. Evaluate **multiplications and divisions** from left to right in the order
   that they appear
1. Evaluate **additions and subtractions** from left to right in the order that
   they appear.

In the absence of grouping symbols, addition holds no precedence over
subtraction and vice versa.

```
15 - 8 + 4 = 7 + 4
					= 11
```

```
15 - 8 + 4 = 15 - 12
					 = 3
```


title: File_system_error_handling_in_Python
last_modified: 2024-10-25 09:31:07
body:
# File system error handling in Python

The [error handler](Error_handling_in_Python.md) in the case of a file not being
found:

```py
try:
    with open('filename.txt', 'r') as file:
    contents = file.readlines()
    for line in lines:
        print(line)
except FileNotFoundError as err:
    print("File does not exist")
    print(err)
```


title: React_errors
last_modified: 2024-10-18 18:55:56
body:
# Errors

## State update on unmounted component

> Can't perform a React state update on an unmounted component. This is a no-op,
> but it indicates a memory leak in your application. To fix, cancel all
> subscriptions and asynchronous tasks in a useEffect cleanup function.

This typically happens when you have an API request running in the background.
Once the data is returned, React tries to update the state but the component is
unmounted.

As the warning suggests, this can be resolved using the cleanup parameter within
[React_useEffect](React_useEffect.md#cleanup-functions).


title: Turing_completeness
last_modified: 2024-10-18 18:55:56
body:
# Turing Completeness

We know that a [Turing machine](Turing_machines.md) is a theoretical construct
of a computer that:

> contains mutable state, executes sequences of simple instructions that read
> and write that state, and can pick different execution paths depending on the
> state (via conditional branch instructions.)

A Turing Complete (TC) system is a system that abides by, or can be reduced to,
the above description.

TC also serves as a _definition of computability_ and provides a formal basis
for conceiving of computation at a theoretical level.

All Turing Complete systems are functionally equivalent. This means they can
simulate each other given enough time and memory. Similarly a TC system can in
principle perform any computation that any other programmable computer can
perform. This is true for _other_ TC systems and also those that are not TC
however the inverse doesn't hold: a non-TC system cannot emulate a TS system.
For instance a calculator cannot do what a TC smart phone can do. But a smart
phone can act as a calculator.

This concept of completeness is also expressed in terms of a Universal Turing
Machine - a TM capable of simulating any other Turing machine. Given that the
ability of a TM to simulate another TM is the condition for completeness, a TC
system is also a UTM.

Completeness applies to the hardware of computers as well as their software.

Turing Completeness is the theoretical basis of the practical concept of a
"general-purpose computer": a general-purpose computer is such because it is
TC - it can in theory compute anything that is computable.

Most modern programming languages are Turing Complete in that they can, in
theory, be used to compute anything that is computable.


title: Multiplying_fractions
last_modified: 2024-10-18 18:55:56
body:
# Multiplying fractions

To find the product of two fractions $\frac{a}{b}$ and $\frac{c}{d}$ multiply
their numerators and denominators and then reduce:

$$\frac{a}{b} \cdot \frac{c}{d} = \frac{a \cdot c}{b \cdot d}$$

### Example

$$
\frac{1}{3} \cdot \frac{2}{5} = \frac{1 \cdot 2}{3 \cdot 5} = \frac{2}{15}
$$

## Prime factorisation in place

The example above did not require a reduction, so here is a more complex
example:

$$
\frac{14}{15} \cdot \frac{30}{140} = \frac{420}{2100}
$$

It would be laborious to reduce such a large product using factor trees or the
repeated application of divisors, as defined in
[reducing fractions](Reducing_fractions.md). We can use a more efficient
method. This method can be applied at the point at which we conduct the
multiplication rather than afterwards once we have the product. We express the
the initial multiplicands as prime factors:

$$
\frac{14}{15} \cdot \frac{30}{140} = \frac{(2 \cdot 7) \cdot (2 \cdot 3 \cdot 5) }{(3 \cdot 5) \cdot (2 \cdot  2 \cdot 7 \cdot 5)}
$$

We now have the product in factorised form before we have applied the
multiplication so we can go ahead and cancel:

$$
\frac{\cancel{2}, \cancel{7}, \cancel{2}, \cancel{3}, \cancel{5}}{\cancel{3}, \cancel{5}, \cancel{2}, \cancel{2}, \cancel{7}, 5} = \frac{1}{5}
$$

**Note that in the above case, there was only a single 5 left as a denominator
and no value left as a numerator. This is equivalent to there just being "one
five" so we write $\frac{1}{5}$**

## Example of multiplying fractions with negative fractions containing variables

Calculate: $$- \frac{6x}{55y} \cdot - \frac{110y^2}{105x^2}$$

First multiply in place:

$$
\frac{(3 \cdot 2 \cdot x) \cdot (5  \cdot 2 \cdot 11 \cdot y \cdot y)}{(5 \cdot 11 \cdot y) \cdot (7 \cdot 5 \cdot 3 \cdot x \cdot x)}
$$

Then cancel:

$$
\frac{(\cancel{3} \cdot 2 \cdot \cancel{x}) \cdot (\cancel{5}  \cdot 2 \cdot \cancel{11} \cdot \cancel{y} \cdot y)}{(\cancel{5} \cdot \cancel{11} \cdot \cancel{y}) \cdot (7 \cdot 5 \cdot \cancel{3} \cdot \cancel{x} \cdot x)} =
\frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x}
$$

Then reduce:

$$
\frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x} = \frac{4y}{35x}
$$


title: The_History_of_Computing_Swade
last_modified: 2024-11-04 15:47:46
body:
# History of Computing (Swade, 2022 )

| Title                                               | Author      | Publication date | Resource type |
| --------------------------------------------------- | ----------- | ---------------- | ------------- |
| The History of Computing: A Very Short Introduction | Doron Swade | 2022             | Book          |

## Timeline

A typical timeline approach rooted in major innovations.

- Ancient aids to counting: knotted cords and notched sticks
- Ancient aids to calculation: counting boards and abacii
- Early mechanical calculator devices in the 17th century (number wheels,
  Pascal, Leibniz)
- Modern aids to calculation: slide rules following the discovery of
  [logarithms](Logarithms.md)
- Mechanised, automated calculating engines of Babbage in the 19th century
- Punched-card machines leading to IBM in the early 20th century
- Analogue and electro-mechanical computers of the early 20th century inclusive
  of wartime computers
- Early valve-based (vacuum-tubed) digital computers (again wartime and early
  Cold War)
- The invention of the transistor and first fully-digital computers
- The invention of [integrated_circuits](Integrated_circuits.md)
- Supercomputers
- Minicomputers
- Consumer personal computers
- Internet and later, Web
- Smart phones

First three phases of digital electronic computers:

- Wartime up to 1950s vacuum-tube era
- Transistor era up to 1963
- First microchip era ending in early 1970s

## Terms

| Term            | Definition                                                                                                                                                                  |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| automatic       | can execute programs, process data and perform functions on its own once it has been started. Can monitor its own processes and make adjustments without human intervention |
| general-purpose | a computer designed to be able to solve a wide variety of problems and perform many different types of tasks as opposed to a computer built for a specific, limited purpose |
| programmable    | the ability to change the operations a computer peforms without physically altering its hardware                                                                            |

## Mechanical calculating devices in the 17th century

Focus was chiefly on creating a desktop calculator capable of four-function
arithmetic.

![Photograph of Pascaline](../img/pascaline.jpg)

![Photograph of replica of Leibniz stepped drum machine](../img/leibniz-stepped-drum.jpg)

The main contenders were the Pascaline of Pascal (which only did cumulative
addition) and the wheel or "stepped drum" calculator of Leibniz that could do
all operations (in theory).

Subsequent designs were based on these artefacts. In practice, neither worked
consistently well with the carriage of tens remaining a sticking point.

![Photograph of Arithmometer](../img/arithmometer.jpg)

![Photograph of Comptometer](../img/comptometer.png)

The arithmometer (crank driven) and comptometer (key-driven) were descendents of
the Leibniz design that became commercially viable by the 19th century along
with other mechanical calculators. In the US, Burroughs dominated the market.

## Babbage: mechanized, automated calculation

> I wish to God these calculations had been executed by Steam (Babbage)

With Babbage's machines we see an approach to computation that can only be
understood against the backdrop of the Industrial Revolution in which they were
conceived.

The idea is that the machine is a factory and number is the product. In the same
way as the mechanised looms created textiles. It is the extension of a model of
industrial production from goods/commodities to information.

Babbage conceived two machines: the Difference Engine (DE) and the Analytical
Engine (AE). Neither were successfully built in his lifetime. The DE preceded
the AE and was basically an advanced mechanical calculator whereas the AE
approximated a general purpose computer.

Despite this, with the Difference Engine, in contrast to preceding _aids to
calculation_, the steps of the computational algorithm were no longer directed
by human intelligence but by internal rules embodied in the mechanism and
automatically generated.

### Difference Engine

The DE's single purpose was to calculate and output mathematical tables such as
the results of polynomial equations. The idea was that you would input the
answer a bell would ring and the machine would _halt_. This influenced Turing
later. It was non-programmable and designed for a specific set of calculations.

### Analytical Engine

Conceived as a general-purpose computing machine capable of performing a wide
range of calculations, programmable using punched cards similar to those used
with Jacquard looms.

It more resembled modern computers in that Babbage used concepts that would
later translate into the [von Neumann architecture](CPU_architecture.md) There
was a "mill" (CPU), "store" (memory) and input/output mechanisms. It also had a
concept of looping and conditional branching.

### Lovelace's insight

A central idea of Ada Lovelace, expressed in her notes on the Analytical Engine
is that **number can represent entities other than quantity**.

If we assign meaning to number, results arrived at by operating on number
according to rules can say things about the world when mapped back onto the
world using the meanings assigned to them.

Lovelace's insight was that the potential of computing lay in the power of
machines to manipulate representations of the world contained in symbols.

## Analogue computers

Both digital and analogue computers are automatic. They differ in _how they
represent quantities_ and how their outputs are derived.

With digital machines, quantity is represented as a string of discrete digits.

With analogue machines, quantity is a physical property _in itself_ rather than
a representation. This could be, for example: the lowering of a weight, the flow
of a liquid, or an electrical charge. This physical behaviour is **analagous**
to the system that is being modelled. Quantities are continuously variable
values rather than discrete (discontinuous values).

Digital machines produce results by _calculation_ whereas analogue machines
produce results by _measurement_, e.g. the height of liquid in a tank or the
time it taks for a tank to be emptied.

### Examples of analogue computers

#### The Phillips Hydraulic Computer

This used fluid to model the workings of the British economy. It consisted of a
series of transparent plastic tanks and pipes which were fastened to a wooden
board.

![Philips Hydraulic Computer](../img/hydraulic_computer.jpg)

Each tank represented some aspect of the UK national economy and the flow of
money around the economy was illustrated by coloured water. At the top of the
board was a large tank called the treasury. Water (representing money) flowed
from the treasury to other tanks representing the various ways in which a
country could spend its money. For example, there were tanks for health and
education. To increase spending on health care a tap could be opened to drain
water from the treasury to the tank which represented health spending.

#### Bush's Differential Analyser

This was designed to solve differential equations by integration. In contrast to
the Philips Computer it was general enough to be used to solve problems from
different contexts. Examples of these contexts: heat flow, ballistics,
mechanics, population growth, chemical interactions, astronomy.

![Differential Analyser](../img/differential_analyser_bush.jpg)

It was about the size of a room and used shafts, motors, discs and wheels to
work.

### Historiography

There is a tendency in the history of computing to downplay or diminish the
contribution of analogue computing devices and to present them as just an
inferior precursor to the inevitable dominance of digital electronic computers.

This is ahistorical and inaccurate.

Analogue (and electromechanical devices) overlapped with and coexisted with
digital devices for 40 years, spanning the first three generations of digital
electronic devices. The term "analogue" itself only came about when the need
arose to distinguish digital devices from other types of computer. They were not
"rivals" before this.

### Electro-mechanical computers

Electro-mechanical devices (also known as "electronic analogue computers") are a
sort of midway between full digital devices and analogue computers, forming a
bridge between the two eras.

Their heyday was roughly 1935 - 1945.

Their key components were:

- [relays](Relays.md) for logic operations
- rotating shafts and gears for performing calculations
- punched cards or paper tape for input instructions and outputs

They were slower than fully digital computers as they were limited by the speed
of moving components rather than the flow of electric charge. In addition the
various mechanical parts were prone to wear and needed frequent replacement.

### Examples of electro-mechanical computers

#### Harvard Mark 1 (1937-1944) - Aikin, IBM

Designed by Howard Aiken and built by IBM (1937-1944). Also known as the
_Automatic Sequence Controlled Calculator_ (ASCC). A general-purpose
electro-mechanical computer it was most famously used at Los Alamos by von
Neumann to calculate the blast yield of the atomic bomb.

![Harvard Mark One](../img/Harvard_Mark_1.jpg)

It was more than 15m in length and weighed 5 tonnes comprising over 750,000
parts. It used paper tape and punched cards for input/output.

#### Complex Number Calculator (1940) - Bell Labs, Stibitz

Not general purpose nor was it programmable. It was hardwired to perform a
specific set of operations on numbers and nothing else. It used relays like the
others. Its distinguishing feature was that it used a teletype for input rather
than cards or paper tape.

![Calculating panel of the CMC](../img/complex-number-calculator-bell-labs.jpg)

![Teletype input of CMC](../img/stibitz-teletype.jpg)

It comprised a panel (the calculating unit) and teletype (the input). One could
remotely access the computer from the teletype in another location, providing it
was connected to Bell Lab's telephone network.

#### Z3 (1941) - Konrad Zuse

![Z3](../img/Zuse-Z3.jpeg)

First designed in 1938 and completed in 1941. Considered the first fully
automatic, programmable digital computer although relay-based. Programs were
stored on external punched tape and binary was used as the number system.
Destroyed by Allied bombing in the War but a replica (pictured) was built
in 1998.

## Vacuum-tube devices

Vacuum-tube devices were the first fully electronic digital devices as they used
vacuum-tubes for implementing binary logic rather than relay switches.

Canonical examples from this era are the ABC computer, the Collossus and most
famously, the ENIAC.

### The Antanasoff-Berry Computer (1939 - 1942)

![ABC Computer](../img/abc-computer.jpg)

Fully automatic, digital electronic computer but not programmable or really
general-purpose, being created to do linear equations. It took decimal input and
output but operated internally using binary arithmetic. The input was punched
cards and the output was via a front-panel display.

Its importance stems from the fact that it was the first to use vacuum-tubes for
the arithmetic calculations of the processor.

### Colossus (1943-1945) - Tommy Flowers/Max Newman

Designed and built at the Post Office Research Station at Dollis Hill. Used for
cracking the Lorenz messages of the German high command.

Mainly important (beyond its role in the War) for establishing the viability of
vacuum-tubes over relays. It comprised 2.4 thousand tubes.

Debatable the extent to which the Collosus can be called the _first digital
computer_ since it was not general purpose and not fully programmable.

Furthermore it was not even a complete solution in its context of application.
The codebreakers would be given a certain advantage using the Collosus
(narrowing the field of possible deciphering keys) but still need to use manual
methods to break the code. It made decipher time shorter rather than executing
the full diciphering. In contrast to, say, the Bombe computer that would
identify the key for the days transmissions.

It's actual influence is also hard to gauge because of the secrecy that remained
in place after the War. Apart from those who worked on it, its technical
advancements were not public knowledge until the late 1970s.

### ENIAC (1945) John Mauchly/J.P Eckert

The _Electronic Numerical Calculator and Integrator_

The main motivation for creating the ENIAC was military: the US Army needed
speed and accuracy when calculating artiliary firing tables and munition
trajectory so that shells could hit their intended targets. Accuracy depended on
myriad factors: gun elevation, shell shape and weight, explosive charge,
distance, wind, temperature etc. Previously this had been done by human
computers under the aegis of the Ballistic Research Laboratory.

![The main control panel of the ENIAC](../img/eniac.jpg)

It was not completed until after VE day but was used at Los Alamos after the War
and retired in 1955.

The BRL commissioned the Moore School of Engineering at the University of
Pennsylvania for the construction of an automatic electronic calculator.

It used vacuum-tubes, along with switches and realys. It used decimal rather
than binary and had punch card input and output. It was crudely programmable and
could be set up to work on different problems by rearranging the different
components using switches and plugboards. But this took roughly two days.

Its design was very influential because it was made public and not classified.

### EDVAC (1944-49) John Mauchly/J.P Eckert/ John von Neumann

Built at the Moore School for the BRL as a successor to ENIAC by Mauchly and
Eckert whilst ENIAC was still operational. It's architecture arose out of
discussions between von Neumann and Mauchly and Eckert and was necessitated by
the need to calculate the behaviour of the fissile materials in the atomic bomb.

It resulted in the famous _First Draft of a Report on the EDVAC_ by von Neumann
which is seen as the definitive statement of the modern **digital programmable
general-purpose computer**.

As a result of the paper, von Neumann effectively got the credit for the
invention even though it synthesised ideas from the ENIAC and the contributions
of others to the EDVAC.

There was lots of disputed provenance and claims of plagiarism generally.
Antanasoff won a legal claim against Eckert and Mauchly for stealing ideas from
the ABC to make ENIAC.

// Add more on the hardware.

### Concept of the _internal stored program_

- Key innovation of the EDVAC was the _internal stored program_ (ISP).

- Solution to the problem of preceding computers requiring down-time when
  switching between applications and problem sets.

- Circuitry would need to be reconfigured before the computer could run on the
  next problem

- ISP removed the friction:

  - the instructions comprising the program would be prepared on tape or punched
    cards and read into electronic memory
  - the hardware configuration of the machine would remain the same accross
    different programs and require no reconfiguration, only the input program
    data would change

- This was basically the invention of software. Both instructions and data
  shared the same memory space once they were read-in. Before, the data would be
  stored in memory but the instructions would be read one-by-one from the
  external storage media.

- Key consequences:
  - flexibility (no need for re-wiring)
  - speed: fetching instructions from memory is quicker than fetching from
    external storage devicde
  - self-modification: since they were in memory, programs could modify
    themselves during their execution (e.g. use branching conditions) and
    treating one program as data for another. This enabled more complex
    algorithms and also opened the possibility of higher-level languages and
    compilers
  - simplified architecture: both programs and data in memory
  - generalisation: computers could switch between different tasks simply by
    loading different programs

### Post-EDVAC devices

There were several notable devices which attempted to implement the architecture
described in the _First Draft_ using vacuum tubes for logic operations and a
variety of different electronic methods for memory:

- the Manchester "Baby"
- the Cambridge EDSAC
- Turing's ACE computer

#### Manchester Baby (1948)

![The Manchester Baby Computer](../img/manchester_baby.png)

- An experimental computer intended to create the
  [von Neumann architecture](CPU_architecture.md) using
  [Williams_Tube_RAM](Williams_Tube_RAM.md)

- Developed at the Univesity of Manchester and completed in 1948.

- Considered the first electronic stored-program computer and first to contain
  all the elements of a modern electronic digital computer.

#### EDSAC (1949) J.Wilkes et al.

![EDSAC](../img/EDSAC.jpg)

- _Electronic Delay Storge Automatic Computer_

- Constructed by Maurice Wilkes and others at the Mathematical Laboratory of the
  University of Cambridge.

- The second digital stored-program computer after the Manchester Baby.

- It used vacuum-tubes for the arithmetical operations in the ALU and mercury
  [delay line memory](Delay_line_memory.md) for the RAM.

- Designed to be used by relatively non-specialist practitioners from other
  university departments who were expected to program it themselves. To this
  end, a formal programming paradigm was forged for the EDSAC which established
  the following:

  - subroutines as a library of common procedures available to programmers (e.g.
    printing a result, reading input tape, program checking, mathematical
    operations)
  - diagnostics: techniques for verifying program code and its correctness

![Programming Digital Electronic Computer book](../img/programming_a_digital_electronic_computter.jpg)

- The key players wrote the first textbook on programming in 1951: _The
  Preparation of Programs for an Electronic Digital Computer_ (Wilkes, Wheeler,
  and Gill)

#### The Automatic Computing Engine (ACE) (1946) Alan Turing

- Technical design provided by Alan Turing working at the Mathematics Division
  of the National Physical Laboratory. The product of Turing's theoretical work
  in "On Computable Numbers" where he proposes the concept of a
  [Turing_machine](Turing_machines.md) and based on his experience with early
  single-purpose computing devices at Bletchley.

- Due to secrecy over wartime work, it was hard for get Turing to build a fully
  electronic implementation since this would disclose advances made during the
  War. Tommy Flowers was intended to be brought in to build it but again this
  was scuppered over the classification of wartime technology. Had this not been
  the case, it is likely it would've been seen as on par with the EDVAC in its
  design, if not dwarfing it.

- Turing proposed a stored program architecture with high-speed memory. It would
  be more perfomant than the EDVAC as a result.

![The Pilot ACE computer](../img/pilot-ace.jpg)

- Turing's actual design was not implemented as it was thought too ambitious
  given how powerful it would need to be. Instead a smaller prototype was made,
  the Pilot ACE. It used vacuum-tubes for logic, and mercury delay lines for
  memory. Data and memory was input via punched cards.

### Further applications of the EDSAC architecture

### LEO I

- Built by Lyons Tea Company to manage business affairs (payroll, inventory,
  stock management)

- Marked a shift from military and academic contexts for computers to business
  and data management.

### IAS machines

![The MANIAC computer](../img/MANIAC_computer.jpg)

Several machines were built at the Institute for Advanced Study utilising the
"von Neumann" architecture and associated advancements such as vacuum-tubes and
Williams' tubes. There was the original IAS machine (1952) as well as the
JOHNNIAC (1954) and MANIAC (1956).

Although their purpose was military (Los Alamos), their designs were public and
widely studied making them influential outside of academia.

### UNIVAC (1951)

![UNIVAC_computer](../img/univac-1.jpg)

Mauchley and Eckert, who had designed the ENIAC left the Moore School and went
into business: Eckert-Mauchley Computer Corporation. This was bought by
Remington Rand and in subsequent years became the main competitor to IBM.

In this capacity they built the UNIVAC: _Universal Automatic Computer_. It's
name being an embodiment of its nature as a general-purpose, electronic digital
computer.

It used vacuum-tubes for logic and mercury delay lines for memory. It had
multiple means of input/output including: directly via an operator console
(basically a typewriter keyboard), magnetic tape for input and output, along
with punched cards.

![UNIVAC operator console](../img/univac-operator-console.jpeg)

It was the first computer specifically designed to include business and
administrative use. This was underscored by its first client: the US Census
Bureau.

A key event was its succesful prediction of the 1952 general election. It
correctly predicted a landslide for Eisenhower (against expectations). (This was
so unlikely, they actually fudged the data because they thought the machine was
way off.) It was a novelty on the results night but it cemented a certain
concept of the computer in the public imagination - large, room sized machines
with blinking lights.

Swade notes that Eckert and Mauchley effectively launched the US commercial
computer industry with the UNIVAC.

## IBM

- First created in 1911 as a merger of four companies all involved in some
  capacity in business data processing. The most significant of these was the
  Hollerith Tabulating Machine Company who's punched card machines had been used
  in the 1890 census, greatly reducing its collation time

- Named IBM in 1924

- UNIVAC represented the encroachment of computing devices into IBM's market of
  punched-card based data-processing and effectively put IBM on notice.

- To attack the threat IBM brought out three crucial machines: the 701, 702
  and 650.

- IBM's approach to marketing their computers was to emphasise the comfort of
  continuity over the shock of the new represented by the UNIVAC. IBM had
  already captured the business market. Their computers would be more of the
  same, just faster and more powerful than their punched card machines due to
  the electronics. To this end they initially did not call their devices
  'computers'.

- IBM were ultimately totally successful in their pivot to the computing market.
  By 1960 it owned over 70% of the data processing and computer market.

### IBM 701 ("Defense Calculator") (1952)

![Control unit of the IBM 701](../img/ibm-701-control-unit.jpeg)

IBM's first electronic computer. It directly competed with the UNIVAC for
government contracts. It followed the prevailing approach of vaccuum tubes for
logic and had a variety of storage methods: Williams tubes,
[magnetic tape](Magnetic_tape.md) , and magentic drums.

701s were used at Los Alamos and avionics companies. Some were also used to
manage payroll in business contexts.

### IBM 702 ("Tape Processing Machine") (1953)

![Advertisement for the IBM 702](../img/ibm-add.jpeg)

Focused primarily on business applications and targetted at businesses rather
than government contracts. Less powerful than the 701.

### IBM 650 (1953)

![IBM 650](../img/ibm-650.jpg)

Low-cost general purpose machine using magnetic drum memory. Marketed as slower
but more affordable than the 700 range. It was mass-produced unlike the others
which were built for specific customers. It was in fact the first mass-produced
computer in the world. It proved the breakout star in IBMs initial line up and
sometimes called "IBM's Model T".

![IBM_650 console panel](../img/ibm-650-console-panel.jpg)

IBM offerred 650s to univesities at a 60% discount on the condition that the
universities would establish courses in computing. This was shrewd as it meant
that a whole generation of engineers and computer scientists learned on 650s and
would prefer them in their research. It also created a pool of skilled users
that would go on to work at IBM.

Donald Knuth dedicated _The Art of Computer Programming_ to the 650.

It used [magnetic drum memory](./Magnetic_drum_memory.md) along with
vacuum-tubes.

### IBM 1401 (1959)

![IBM 1401](../img/ibm-1401.jpg)

Another IBM mainframe. Transistors replaced vacuum-tubes. Magnetic core storage
replaced magnetic drum storage. It was housed in rectangular light-blue cabinets
and the ubiquity of the 1401 in industry earned IBM the moniker 'Big Blue'.

### IBM System/360 (1964)

![IBM 360](../img/ibm-360.jpg)

Named to suggest all-round compatibility - a family of mainframes designed to
cover commercial and scientific applications. Considered one of history's most
successful computers.

Up until this point all IBM computers had a programming language unique to the
specific processor. At that point there were about seven IBM computer models in
active use and they were all incompatible with each other.

![IBM 360 promo poster](../img/ibm-360-in-use.jpeg)

In contrast the 360 computers all used the same programming language. This meant
they were interoperable with each others. Because the there were variants in the
360 ranges, customers could purchase a smaller system knowing they could expand
it if their needs grew, without reprogramming their application software.

## Magnetic core devices: Whirlwind and SAGE

Two devices that leveraged the new technology of
[magnetic_core_memory](Magnetic_core_memory.md) where the Whirlwind and SAGE
computers. The ENIAC was also updated to use magnetic cores.

![Whirlwind magnetic core memory](../img/whirlwind-magnetic-cores.JPG)

The Whirlwind computer (1953) was a flight simulator and the first to use
magnetic cores. Crucially was able to operate in realtime for output.

The SAGE computer (_Semi-Automatic Ground Environment_) emerged as a response to
the Soviet acquisition of the atomic bomb in 1949. The Americans realised they
needed a much better early warning and air defence system that would allow them
to identify bombers in their airspace and dispatch fighters.

To achieve this, it was necessary to detect enemy bombers with radar and compute
an interception course. Alterations in the bomber flight path required
continuous updates and real-time computation of directions for the responding
fighter.

The resulting computer was SAGE (made by IBM) which was modelled on Whirlwind,
using magnetic cores. SAGE computers were spread accross the continental US in
sectors and managed by NORAD.

![SAGE command post](../img/SAGE_command_post.jpg)

The SAGE system was operation between 1958-1984, receiving continual
improvements and updates. In addition to magnetic cores it introduced many
technological innovations that influenced computers generally: interactive
screens, printed circuit boards, mass-storage devices, digital communication
over telephone lines, time-sharing, along with advances in software.

Because so many private companies worked as contractors on SAGE (IBM, Burroughs,
Bell Labs, RAND Corp), the military technology (both hardware and software) made
its way from the military context to business and consumer computing.

An example of a civilian application of SAGE technology was airline booking
systems, where booking reservation data needed to be processed in realtime. IBM
worked with American Airlines to introduce this.

## Transistor and integrated circuit revolution

The arc of modern computing history (and its main eras) can be presented as

- vacuum-tubes
- [transistors](Transistors.md)
- [integrated_circuits](Integrated_circuits.md)

The transistor was invented at Bell Labs in 1947 by William Shockley and others.
They were not created with computers in mind. Instead they were first used in
hearing aids (1953) and transistor radios (1954).

From the mid-1950s onwards they started being used in military computers.

They had several advantages over vacuum-tubes: they were durable and reliable
with no required startup time, they were power efficient and small.

The actual period where transistors alone were supreme in the form of a
transistor board was relatively short-lived and rapidly gave way to ICs.

Computers of the transistor era had the following components separate from each
other: the transistors, wired connections, resistors and capacitors. Integrated
circuits put these all on the same piece of silicon.

They were first manufactured by Fairchild Semiconductor which was an offshoot of
Shockley's Shockley Semiconductor Laboratory.

The initial marked for ICs was military and scientific: the Minuteman ICBM and
computers of the Apollo spacecraft. This laid the groundworkd for later
commercial use and the personal computer revolution.

## Mini-computers

Mini computers did not threaten mainframes but they opened up a new class of
user. They were vastly cheaper than a mainframe and only the size of a small
fridge.

The main player was DEC (Digital Equipment Corporation) starting in the
mid-1960s. The introduced the PDP-8 in 1965 (Programmed Data Processor). The
PDP-8 used transisotrs and magnetic core memory. It was affordable to smaller
businesses if not yet, consumers.

![The PDP-8](<../img/540px-PDP-8_(1).jpg>)

The internals were made public and DEC encouraged making the machine extensible
by users being permitted to create their own programs and specialised
applications. This was a very different culture to IBM where technicians were
required and machines were typically leased.

By 1988, DEC was the second largest computer company after IBM. This led to
additional companies entering the mini-computer market: Data General, Honeywell,
Hewlett-Packard.

Mini-computers died as a category in the mid-1990s in the wake of the PC.

## The Personal Computer

The PC emerged out of advances in IC chip design - this was the engine of the
PC.

Intel (newly founded by Robert Noyce and Gordon Moore) were charged with making
custom chips for a Japanese calculator company. Instead of creating the custom
chips, they advised the company to use a general purpose chip that could handle
general computing as well as the basic calculator functions. This generic chip -
the Intel 4004 - was the microprocessor combined with three other ICs
(comprising 2.3k transistors) that comprised the fundamental building blocks of
the von Neumann architecture.

![Intel 4004 chip](../img/intel-4004.jpg)

However it took until the Apple II in 1977 for the phrase "personal computer" to
enter the lexicon and become an identifiable class.

The broader context for this was the computer hobbyists in Silicon Valley/Menlo
Park (particularly the Homebrew Club of amateur computer engineers) along with
idealistic figures from the 60s counterculture (such as Stuart Brand) who began
associating computing technology as a tool of personal liberty and fulfillment.

### Microsoft and Apple

The PC "boom" began with the Altair 8800. This was a mail-order kit that
required manual assembly. It was released by Micro Instrumentation Telemetry
Systems (MITS) in 1975. It couldn't do much but had expansion capability
(memory, teletype interface, casette player for data storage).

![Altair 8800](../img/altair-8800.jpg)

Bill Gates and Paul Allen made a proposal to MITS: they would write software
that would allow users to program the Altair in BASIC. They agreed and were
prepared to distribute the software. As a result Gates and Allen founded
Microsoft in 1975.

Around the same time, Steve Wozniak (member of the Homebrew club) built the
Apple I as a single-board hobbyist project. He made this available to buy via
mail order and formed Apple with Steve Jobs in 1976 to manage the enterprise.

![Apple I](../img/apple1.jpg)

By 1977 they had investment capital and brought out the Apple II. This was sold
preassembled with casing and required no soldering. It had expansion slots for
third-party vendors to create compatible devices and had colour graphics.

The design of the Apple II was published in _Byte_ in order to invite
crowd-sourced plugins and extensions. One of these was the Z-80 softcard which
allowed it to run the CP/M OS (created by the company Digital Research) giving
ready-made access to software such as a word-processor, spreadsheets and
databases.

![Apple 2](../img/apple2.jpg)

Other competitors in the PC market at this time were Radioshack's TRS-80 and the
Commodore PET.

### IBM

All the while it was hobbyist and tinkerers driving the PC market, IBM had no
real interest. When PCSs started being used by businesses and their capacity
grew to include typical business applications (databases, spreadsheets) it
sensed an incursion into its market.

![IBM PC](../img/ibm-pc.jpg)

Thus, in 1981, IBM launched the "IBM Personal Computer" which rapidly became the
industry standard. This had the effect of legitimising the concept of a PC.
There was overwhelming demand. In their marketing IBM melded home and office use
to capture both markets at once.

The internal specification of the IBM PC was freely available (dubbed 'open
architecture'), in contrast to IBM's business computers, to encourage software
expansion. Cards could be created to fit in its expansion slots adding graphics,
sound, additional memory and networking capability.

IBM originally contracted Digital Research to create software based on CP/M but
this fell through. Microsoft got the deal to supply the OS which became MS-DOS
(Microsoft Disk Operating System). Henceforth every PC and PC-clone came with
DOS bundled.


