# entries

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: 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: 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: 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: 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: Biconditional_Elimination
last_modified: 2024-10-18 18:55:56
body:
# Biconditional Elimination

Give that the biconditional means that if $P$ is the case, $Q$ must be the case
and if $Q$ is the case, $P$ must be the case, if we have $P \leftrightarrow Q$
and $P$, we can derive $Q$ and vice versa.

![](/img/biconditional-elim.png)


title: Useful_operators_in_SQL
last_modified: 2024-10-18 18:55:56
body:
# Useful operators in SQL

## True and false

> In SQL false results are represented by `0` and true results are represented
> by `1`. Any zero value is false and any non-zero value is true.

> When comparing operators we can use `SELECT` as a general "execute" function
> for SQL to interpret

```sql
SELECT 0 = 0 -- 1
SELECT 0.0 = 0 -- 1
SELECT 9 >= 12 -- 0
```

## Boolean operators

SQL supports all Boolean operators:

```sql
SELECT (9 > 7) AND (3 < 5) -- 1
SELECT (3 > 1) OR (2 > 5) -- 1
SELECT (3 > 1) XOR (5 > 1) -- 0
```

We also have `IS` and `IS NOT` for testing Boolean values:

```sql
SELECT (9 > 7) IS TRUE -- 1
SELECT (9 > 7) IS NOT TRUE -- 0
```

## `NULL`

- `NULL` is neither true (1) or false (0). It has no value.
- An empty string (`""`) is **not** `NULL`

```sql
SELECT 1 IS NULL -- 0
SELECT 1 IS NOT NULL -- 1
SELECT NULL IS NULL -- 1
SELECT "" IS NULL -- 0
```


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: Boolean_algebra
last_modified: 2024-10-18 18:55:56
body:
# Boolean algebra

## Algebraic laws

Many of the laws that obtain in the mathematical realm of algebra also obtain
for Boolean expressions.

### The Commutative Law

$$
    x \land y = y \land x \\
$$

$$

    x \lor y = y \lor x
$$

Compare the
[Commutative Law](Whole_numbers.md#the-commutative-property)
in the context of arithmetic.

### The Associative Law

$$
    x   \land (y \land z) = (x \land y) \land z
$$

$$
    x   \lor (y \lor z) = (x \lor y) \lor z
$$

Compare the
[Associative Law](Whole_numbers.md#the-associative-property)
in the context of arithmetic.

### The Distributive Law

$$
    x \land (y \lor z) = (x \land y) \lor (x \land z)
$$

$$
    x \lor (y \land z) = (x \lor y) \land (x \lor z)
$$

Compare how the
[Distributive Law applies in the case of algebra based on arithmetic](Distributivity.md):

$$
    a \cdot (b + c) = a \cdot b + a \cdot c
$$

### Double Negation Elimination

$$
    \lnot \lnot x = x
$$

### Idempotent Law

$$
    x \land x = x
$$

> Combining a quantity with itself either by logical addition or logical
> multiplication will result in a logical sum or product that is the equivalent
> of the quantity

### DeMorgan's Laws

In addition we have
[DeMorgan's Laws](DeMorgan's_Laws.md) which express
the relationship that obtains between the negations of conjunctive and
disjunctive expressions:

$$
\lnot(x \land y)  = \lnot x \lor \lnot y
$$

$$
    \lnot (x \lor y) = \lnot x \land \lnot y
$$

## Applying the laws to simplify complex Boolean expressions

Say we have the following expression:

$$
    \lnot(\lnot(x) \land \lnot (x \lor y))
$$

We can employ DeMorgan's Laws to convert the second conjunct to a different
form:

$$
    \lnot (x \lor y) = \lnot x \land \lnot y
$$

So now we have:

$$
    \lnot(\lnot(x) \land (\lnot x \land \lnot y ))
$$

As we have now have an expression of the form _P and (Q and R)_ we can apply the
Distributive Law to simplify the brackets (_P and Q and R_):

$$
    \lnot( \lnot(x) \land \lnot(x) \land \lnot(y))
$$

Notice that we are repeating ourselves in this reformulation. We have
$\lnot(x) \land \lnot(x)$ but this is just the same $\lnot(x)$ by the principle
of **idempotence**. So we can reduce to:

$$
    \lnot(\lnot(x) \land \lnot(y))
$$

This gives our expression the form of the first DeMorgan Law
($\lnot (P \land Q)$), thus we can apply the law ($\lnot P \lor \lnot Q$) to
get:

$$
\lnot(\lnot(x)) \lor \lnot(\lnot(y))
$$

Of course now we have two double negatives. We can apply the double negation law
to get:

$$
    x \lor y
$$

### Truth table

Whenever we simplify an algebraic expression the value of the resulting
expression should match that of the complex expression. We can demonstrate this
with a truth table:

| $x$ | $y$ | $\lnot(\lnot(x) \land \lnot (x \lor y))$ | $x \lor y$ |
| --- | --- | ---------------------------------------- | ---------- |
| 0   | 0   | 0                                        | 0          |
| 0   | 1   | 1                                        | 1          |
| 1   | 0   | 1                                        | 1          |
| 1   | 1   | 1                                        | 1          |

### Significance for computer architecture

The fact that we can take a complex Boolean function and reduce it to a simpler
formulation has great significance for the development of computer
architectures, specifically
[logic gates](Logic_gates.md). It
would be rather resource intensive and inefficient to create a gate that is
representative of the complex function. Whereas the simplified version only
requires a single
[OR gate](Logic_gates.md#or-gate).


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: Functions_in_Bash
last_modified: 2024-10-18 18:55:56
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

```sh
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: Primitive_types
last_modified: 2024-10-18 18:55:56
body:
# Primitive types

The most basic type level is the one already present in JavaScript itself: the
primitive data types: `boolean`, `string` and `number` . These are the types
that would be returned from a `typeof` expression in ordinary JavaScript

## Type inference

You can explicitly declare these data types yourself when you create a variable
with `var`, `const`, or `let` if you like, but it is generally unnecessary since
Typescript is intelligent enough to perform **type inference** and will know
from what you write which type you mean.

```ts
const age: number = 32;
const name: string = "Thomas";
const one: boolean = true;
const zero: boolean = false;
```

## Arrays

With arrays that you directly define the type will also be inferred but it can
be helpful to explicitly declare them. If you declare an empty array, it is
necessary to assign empty brackets.

```ts
const store: number[] = [1, 2, 3]; // Populated array
const store: string[] = []; // Empty array
```

## Object

`Object` is a valid type declaration in TS but it is not particularly helpful
since it becomes similar to using [any](Any.md) given that most primitive
types in JavaScripts prototypically inherit from an Object.

Generally, when you use objects in TypeScript you type them as
[custom types](Custom_types_in_TypeScript.md).

## Array of (untyped) objects

If we just know that it is going to be an array of objects we can use:

```ts
const arrOfObj = {}[]
```

If we wish to define a particular shape but without defining a type:

```ts
const arrOfObj = { name: string, age: number }[]
```

But better for reusability to do:

```ts
type ArrayOfObj = {
  name: string,
  age: number
}

const arrOfObj: ArrayOfObj[] = [{}, ...]

```


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

You can think of S3 as an external mounted harddrive for storing raw binary data
(images, soundfiles, documents etc).

Your use of the S3 service is divided up into **buckets**. Buckets contain files
and resources. These are just resource names in an online container, the data
doesn't have any structure beyond that.

The primary use of S3 is to store resources that an application needs and/or to
facilitate the uploading and downloading of resources to and from an
application.

You can set access and authentication conditions for buckets, making the data
public or restricted.


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: Passing_arguments_and_options_to_Bash_scripts
last_modified: 2024-10-18 18:55:56
body:
# Passing arguments and options to Bash scripts

## Relation between commands and programs

Whenever we issue a command in bash we are running an executable program that
the command token references. This is why when we create our own bash scripts we
must run `chmod` to make them executable. When we issue a command like
`./do_something.sh` we are running an executable program.

When we run a program like `cd` or `npm` we don’t have to type `./cd.sh` or
`./npm.sh`. This is because a reference to the program file is already in our
[`$PATH`](The_PATH.md).

In the case of `cd`, this is an in-built program and as such it will be sourced
from a binary and we have a reference to the binary in path. In the case of
`npm`, this is not an in-built program however in order to run it we must
already have it in our `PATH`.

## Passing arguments

A script is really just a function that runs when you source it. As such there
needs to be a way for you to pass data to the function so that it can actually
act like a function and take arguments. When we use for example `cd ./Desktop`
we are passing a directory name as an argument to the `cd` program. We can do
the same thing with our custom bash scripts.

To pass an argument we simply add the values after the script in the command.
For example:

```bash
./arguments.sh Thomas 33
```

We can use built-in variables to return information about the invocation of this
script:

```bash
#!/bin/bash

echo "File is called $0"
echo "The arguments provided are $@"
echo "The first argument is $1"
echo "The second argument is $2"
echo "Your name is $1 and you are $2 years old"
echo "There were $# arguments"
```

This outputs:

```
File is called ./arguments.sh
The arguments provided are Thomas 33
The first argument is Thomas
The second argument is 33
Your name is Thomas and you are 33 years old
There were 2 arguments.
```

Key points:

- `$0` designates the script or function that is being executed
- `$@` designates a list of all the arguments that are passed to the script
- `$1...` designates each individual argument
- `$#` gives us a count of the number of arguments

## Passing options

Options differ from arguments in that they are prepended with `-` and they can
be passed in any order. We use the `getops` program to parse the options that
the user inputs with their command.

We can demonstrate this with a script that takes in a username and password as
options.

We can handle an option-based input like:

```
some-program -u thomas -p password123
```

With the following construct:

```sh
while getopts u:p: option; do
  case $option in
    u) user=$OPTARG;;
    p) pass=$OPTARG;;
  esac
done

echo "user: $user / pass: $pass"
```

Which returns:

```
user: thomas / pass: password123
```

Here we set up a `while` loop against the `getopts` command to parse the options
in the stdin and store each one in a `option`. We run each `option` through a
case statement and individuate each one, storing them in dedicated local
variables via the global `$OPTARG` variable

### The role of the colons

Using a colon after each option means that the script will expect the given
option to have a value. If we put a colon _before_ each of the options we expect
this will allow us to view any option the user provides in our option handler.
This is useful when you are working with very many options, as with a
command-line program.

This version demonstrates a more exhaustive use case:

```sh
while getopts :u:p: option; do
  case $option in
    u) user=$OPTARG;;
    p) pass=$OPTARG;;
    a) echo "got the 'a' flag";;
    b) echo "got the 'b' flag";;
    ?) echo "Don't know what $OPTARG is!"
  esac
done

```


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: f6564af9_AOL_and_early_internet_enclosure
last_modified: 2024-11-04 18:33:47
body:
# f6564af9_AOL_and_early_internet_enclosure

We might view AOL, with its ubiquitous 'free trial' CD-ROMs, as the first
attempt by a corporate entity to try and enclose the Internet/Web. To take the
vast informational expanse and reduce it to a single, filtered and contained
space controlled by a single company.

![Early AOL interface](../img/aol-on-windows.jpg)

_AOL interface from 1993_

This would later be achieved or approximated more effectively by Google (under
the guise of doing the opposite - people are "empowered" to access the
information they otherwise would not find, granted a key to the Internet etc.
When in fact, making everyone go through the same gate enables surveillance and
the monetisation of the use of a public resource) and then of course by the
social media companies.

AOL in fact started this even before there was a Web, pioneering the concept of
a web portal, with their [modem-based](cfbef1c4_web_precursors.md) private-BBS
business model. This provided access to a circumscribed subset of the Internet
at a time when accessing information was opaque and confusing to the average
non-technical user. The advent of the web first threatened and then basically
obviated this model, when access to information via browsers and HTTP servers
made the process easier and more democratized. Hence why AOL then tellingly
pivoted to the browser and search-engine market (purchasing
[Netscape](c301a0b3-1d8_Mosaic_Netscape_and_Browser_Wars.md) in 1999), the next
available mechanism of enclosure.

![AOL homepage](../img/aol-original.jpg)

_AOL interface from 1999_


title: Algebra_key_terms
last_modified: 2024-10-18 19:11:02
body:
# Algebra key terms

- **Variable**
  - A symbol that stands for a value which may vary
- **Equation**
  - A mathematical statement that equates two mathematical expressions (states
    that they are the same/ establishes an identity relation)
- **Solution** ^678811
  - A numerical value that **satisfies** an equation. When the variable in the
    equation is replaced by the solution, a true statement results

### Example

$$ 4 = y - 11 $$

The example above is an **equation**. $y$ is the variable. This can be replaced
by $15$ which is the **solution** to the equation:

$$ 4 = 15 -11 $$


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: 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: What_are_disks
last_modified: 2024-10-18 18:55:56
body:
# What are disks?

A disk is a mass storage [block_device](Devices.md) which we
can write to and read from.

## SCSI

- Small Computer System Interface, responsible for handling disk access on most
  Linux systems.
- It is a protocol that allows communicaton between printers, scanners and other
  peripherals in addition to harddisks.

## Disk schematic

The following diagram represents the basic anatomy of a disk device.

![](/img/harddisk.png)

- A disk is divided up into [partitions](Partitions.md)
  which are subsections of the overall disk. The kernel presents each partition
  as a [block device](Devices.md) as it would with an entire
  disk.
- The disk dedicates a small part of its contents to a **partition table**: this
  defines the different partitions that comprise the total disk space.
- The **filesystem** is a database of files and directories: this comprises the
  bulk of the partition and is what you interact with in
  [user space](User_Space.md) when reading and writing data.


title: Elastic_Compute_Cloud
last_modified: 2024-10-18 18:55:56
body:
# Elastic Compute Cloud (EC2)

- Cloud-based or virtual server (virtual machine), basically a hypervisor
  (compare [[zk/Docker_architecture]])
- It is virtual because you are not responsible for its physical implementation
- Still needs considerable configuration compared to a serverless
  [[zk/Lambda_programming_model]]
- Like lambdas has the benefit of easy scaling: you can add compute capacity on
  demand (elasticity)

The following needs to be considered:

- Naming
- Application and OS image (known as "Amazon Machine Image"):
  - Which OS you want to use (Linux distribution, Windows, etc)
  - Applications you want pre-installed
  - Block device mapping
- Instance type an size (basically the type of processor and how powerful you
  want it to be)
- An encrypted key-pair for login
- Your network (typically managed via Amazon VPC (Virtual Private Cloud)) and
  network security
- Storage: size and type (eg. GP3)
- Location and latency

> EC2 is more expensive copared to serverless options. Accordingly it is better
> to run smaller servers (in terms of processor and memory) at higher capacity
> than larger servers under-capacity.


title: Type_hinting
last_modified: 2024-10-18 18:55:56
body:
# Type hinting in Python

With type hinting we can add type information to variables, functions, and
classes. This is not enforced by the Python interpreter but can be used by
external tools like `mypy` to check the code.

Prior to 3.10, to use types you would have to import the types you wanted `from`
the `typing` module. With later versions you can use them directly without
importing from `typing`.

## Basic syntax

### Variables

```py
name: str = "John"
age: int = 30
```

### Functions

```py
def greet(name: str) -> str:
    return "Hello, " + name
```

### Classes

// TODO: Add examples

## Complex data types

We can type complex data types such as dictionaries, lists, tuples etc.

The following function takes a tuple comprising two integers as a parameter and
returns a list of ints:

```py
def populate_pair_values(pair: tuple[int, int]) -> list[int]:
    return [i for i in range(pair[0], pair[1] + 1)]
```

## Custom dictionary types

We can create custom dictionary types in the manner of TypeScript types and
interfaces as follows:

```py
class ArticleInfo(TypedDict):
    timestamp: str
    article_    link: str
```

We could then use it thus:

```py
def parse_articles() -> list[ArticleInfo]:
```

## Optional types

`Optional` can be used to indicate that a variable can be `None` or the
specified type.

```py
from typing import Optional

def find_index(numbers: list[int], target: int) -> Optional[int]:
    try:
        return numbers.index(target)
    except ValueError:
        return None
```

The function above returns an `int` or `None`.

Post 3.10, we don't need to use `Optional`, we can use a union to cover the
`None` case. Refactoring the previous example:

```py
def find_index(numbers: list[int], target: int) -> int | None:
    try:
        return numbers.index(target)
    except ValueError:
        return None
```

## Union types

`Union` can be used to indicate that a variable can be one of several types.

```py
from typing import Union

def add(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
    return a + b
```

The function above returns an `int` or `float`.

> Note that in the case of `Optional` and `Union` the type is specified using
> square brackets. This is a syntactic covnention and does not denote that the
> return type is a list. Below is an example of how we would use type hinting to
> indicate that the return type actually is a list:

```py
from typing import List, Union
def my_function() -> List[int]:
    return [1, 2, 3]

# And to show a return type of a list of integers or floats:

def my_function() -> List[Union[int, float]]:
    return [1, 2, 3]
```

Post 3.10 we can use `|` syntax instead of importing `Union`. E.g:

```py

def add(a: int | float, b: int | float) -> int | float:
    return a + b
```


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.


title: Internet_fundamentals
last_modified: 2024-10-18 18:55:56
body:
# Internet fundamentals

The internet is a _[network](Network_fundamentals.md) of networks_. A globally
connected set of computer networks that all use a suite of common
[protocols](Network_protocols.md).

The protocols governing the communication between networks on the internet are
specified in the **Internet Protocol Suite**.

This combines two protocols:

- **TCP**
  - The Transmission Control Protocol
- **IP**
  - The Internet Protocol

Hence the Internet Protocol Suite is also known as "TCP/IP".

The TCP/IP is a network stack comprising four layers, each with its own
protocols. From the top:

![TCP/IP stack diagram](../img/TCP_IP.png)

- The [Link Layer](Link_Layer_of_Internet_Protocol.md) concerns communication
  between devices on the same local network. The transfer of information once it
  has been received from the internet or its transfer between devices before it
  sent out into the internet. Ethernet and WiFi are two core protocols utilised
  at this layer.

- The [Internet Layer](Internet_Layer_of_Internet_Protocol.md) is concerned with
  communication accross networks. It is responsible for identifying hosts on the
  inter-network by their addresses and routing data from network to network.

- The [Transport Layer](Transport_Layer_of_Internet_Protocol.md) creates a
  commmunication channel between two hosts using ports and sockets.

- The [Application Layer](Application_Layer_of_Internet_Protocol.md) concerned
  with software that utilises information received and sent over the internet,
  for instance web pages and emails. This is the highest level of abstraction
  for which all the lower levels serve as "plumbing". Examples of protocols
  operative at the Application Layer include HTTP and SSH.

See:
[Example_scenario_internet_data_transfer](Example_scenario_internet_data_transfer.md)


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: Wildcards_in_SQL
last_modified: 2024-10-18 18:55:56
body:
# Wildcards in SQL

SQL does not use Regex. Instead it has a simpler glob-like syntax for carrying
out string matching.

In order to signal that you wish to compare by a wildcard and not a value, you
have to use the `LIKE` keyword. The actual wildcard operator is `%` .

In an SQL statement, the `%` wild card will match any number of occurrences of
any character. Any characters can appear before or after ‘MacBook’ and the
record will still be returned:

```sql
SELECT name, cores, release_date
FROM model
WHERE name LIKE '%MacBook%';
```

This wildcard only filters characters that come after `Raspberry` :

```sql
SELECT name, cores, release_date
FROM model
WHERE name LIKE 'Raspberry%';
```


title: Working_with_CSVs_in_Python
last_modified: 2024-10-19 10:02:12
body:
# Working with CSVs in Python

## Core package

```py
import csv
```

## Read and write to CSV

### Read

Use standard Pythonic "read" syntax:

```py
with open('./path.csv', mode="r") as csv_file:
    reader = csv.reader(csv_file)
```

### Parse values

Having created the `reader` object, you can then loop through this as an
iterable:

```py
for row in reader:
    print(row)
```

Will return something like:

```csv
column something, column something else, ...
```

Which we can individuate with:

```py
print(row[0])
# column something
```

We can also parse the rows as a dictionary for easier individuation. We do this
by creating a `DictReader` rather than the default `reader`:

```py
...
dict_reader = csv.DictReader(csv_file)
```

Now we can use the header row values to individuate particular columns.

Say we have a CSV with the following headers:

```csv
name, profession
```

We can individuate thus:

```py
for row in dict_reader
    name = row["name"]
```

### Write

Use standard Pythonic "read" syntax:

```py
with open('./new_csv_file.csv', mode="w") as csv_file:
    writer = csv.writer(csv_file)
```

The above will create the file as well, it doesn't need to be pre-existing.

This creates the writer object. To actually write a row:

```py
some_list = ['thomas', 'engineer']
for element in some_list:
    writer.writerow(element)
```


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: 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: 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: Grep
last_modified: 2024-10-18 18:55:56
body:
# Grep

## Purpose of `grep`

`grep` stands for “global regular expression print”. It allows you to search
plain text data sets for strings which match a regular expression or pattern.

## Syntax

### Schematic

```bash
grep [options] [pattern] [source file] > [output file]
```

Note that above we redirect the file matches to a new file. You don't have to do
this. If you omit the redirection, `grep` will output to standard output.

### Applied

```bash
grep -i -n "banana" fruits.txt > banana.txt
```

The above example searches, using regex, for strings matching the pattern
“banana” in the file `fruits.txt` regardless of the character case (`-i` ensures
this) and outputs its findings to the file `banana.txt`, with the line number
where the match occurs appended to the output (`-n` takes care of this).

Note that for simplicity, you can chain optional values together, i.e. the
options in the above example could be input as `-in`.

## Useful options

- ignore case: `i`
- count matches instead of returning actual match: `-c`
- precede each match with the line number where it occurs: `-n`
- invert the match (show everything that doesn't match the expression): `-v`
- search entire directories recursively: `-r`
- list file names where matches occur (in the scenario of a recursive match):
  `-l`

## `ripgrep`

`ripgrep` is generally faster however it does not come as default with Unix and
only works recursively, i.e. it is designed to find strings within files within
multiple directories not just single files or piped streams.

It also respects `.gitignore` files that it finds within directories by default
and `node_modules` which is really handy.

Most of the standard `grep` options transfer over.


title: Working_with_JSON_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Working with JSON in Python

## `json.loads()`

Convert a string containing JSON data into the native Python dictionary object.
Equivalent to `JSON.parse()` in JavaScript.

Will error if the input string is not properly formatted JSON. This will be
`json.JSONDecodeError`, a subclass of the `ValueError`
[exception](./Error_handling_in_Python.md)

## `json.dumps()`

Take a JSON-formatted dictionary and convert it into a string. The reverse of
`json.loads()` and equivalent to `JSON.stringify()` in JavaScript.

## JSON errors

The `.loads()` and `.parse()` methods will throw an error if the input string is

## Related notes


title: Factory_pattern
last_modified: 2024-10-18 18:55:56
body:
# Factory pattern

The factory pattern pertains to how objects are created in the course of the
code. It is class based.

In this pattern we create a class interface that delegates the responsibility of
object instantiation to its subclasses.

You have a high level class that sits on top of two or more lower level classes
that are semantically related but different in function. Depending on the input
the higher level class receives upon instantiation, it will generate one of the
lower level classes.

### Advantages

- allows for dynamic creation
  - we may not know what objects are required until runtime: the factory allows
    us to cover several eventualities
- decoupling
  - in cases where the lower level classes combine to create something greater
    than their individual parts (see the Alligator example below), they do not
    have to know about each other.
- maintenance
  - allows us to add/remove new object classes easily without changing a lot of
    code.

## Examples

We have two types of notification: email and push. The creation of these two is
handled by a factory class called `NotificationFactory` :

```jsx
class PushNotification {
  constructor(sendTo, message) {
    this.sendTo = sendTo;
    this.message = message;
  }
}

class EmailNotification {
  constructor(sendTo, cc, emailContent) {
    this.sendTo = sendTo;
    this.cc = cc;
    this.emailContent = emailContent;
  }
}
```

```jsx
class NotificationFactory {
  createNotification(type, props) {
    switch (type) {
      case "email":
        return new EmailNotification(
          props.sendTo,
          props.cc,
          props.emailContent
        );
      case "push":
        return new PushNotification(props.sendTo, props.message);
    }
  }
}
```

We first instantiate an instance of the factory and then pass into it the
parameters for either of the two lower level classes.

```jsx
const factory = new NotificationFactory();

// create email notification
const emailNotification = factory.createNotification("email", {
  sendTo: "receiver@domain.com",
  cc: "test@domain.com",
  emailContent: "This is the email content to be delivered.!",
});

// create push notification
const pushNotification = factory.createNotification("push", {
  sendTo: "receiver-device-id",
  message: "The push notification message",
});
```

This example doesn't use a constructor on the factory class, but we could easily
do so. This would remove the need to call a method on the factory class when we
want to instantiate one of the subclasses. Here is another example that does
this with an alligator factory:

```jsx
class ReptilePartFactory {
  constructor(type, props) {
    if (type === "tail") return new TailFactory(props);
    if (type === "torso") return new TorsoFactory(props);
    if (type === "head") return new HeadFactory(props);
  }
}

let alligator = {};
let alligatorProps = {
  tailLength: 2.5,
  color: "green",
  snoutLenth: 1,
};

//gets a tail from the tail factory
alligator.tail = new ReptilePartFactory("tail", alligatorProps);

//gets a torso from the torso factory
alligator.torso = new ReptilePartFactory("torso", alligatorProps);

//gets a head from the head factory
alligator.head = new ReptilePartFactory("head", alligatorProps);
```


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: Package_management_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Package management

## List installed packages

```bash
npm list
```

This will return a recursive tree that lists dependencies, dependences of
dependencies, ... and so on. To limit the depth you can add the `--depth=` flag.
For example to see only your installed packages and their versions use
`npm list --depth=0`.

## View `package.json` data for an installed package

We could go to the NPM registry and view details or we can quickly view the
`package.json` for the dependency with the command `npm view [package_name]`

We can pinpoint specific dependencies in the `package.json`, e.g.
`npm view [package_name] dependencies `

## View outdated modules

See whether your dependency version is out of date use `npm outdated`. This
gives us a table, for example:

![Pasted image 20220411082627.png](Pasted_image_20220411082627.png)

- _Latest_ tells us the latest release available from the developers
- _Wanted_ tells us the version that our `package.json` rules target. To take
  the first dependency as an example. We must have set our SemVer syntax to
  `^0.4.x` since it is telling us that there is a minor release that is more
  recent than the one we have installed but is not advising that we update to
  the latest major release.
- _Current_ tells us which version we currently have installed regardless of the
  version that our `package.json` is targeting or the most recent version
  available.

## Updating

`npm update` only updates from _current_ to _wanted_. In other words it only
updates in accordance with your caret and tilde rules applied to
[semantic versioning](Semantic_versioning.md).


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: 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: 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: 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: Generics_in_TypeScript
last_modified: 2024-10-18 18:55:56
body:
# Generics

Generics are a powerful feature in TypeScript that enables you to write reusable
and flexible code while maintaining strong typing. With generics, you can create
functions, classes, and interfaces that work with various types while preserving
type information.

The main purpose of generics is to allow developers to write code that can
**operate on different data types without knowing the specific type
beforehand**. This helps to keep the code DRY and maintainable.

## Basic usage

### Functions

```ts
function identity<T>(arg: T): T {
  return arg;
}
```

Here, `T` is a generic type variable. The `identity` function is a generic
function that takes an argument of type `T` and returns a value of type `T`.

To use this generic function you can either explicitly provide the type within
the angle brackets, or let TypeScript infer the type based on the value passed:

```ts
// Explicitly specifying the type
let output1 = identity<string>("hello");

// TypeScript infers the type as `number`
let output2 = identity(42);
```

#### Restricting the available types

In the previous example any type could be used with the `identity` function. The
only constraint that we place on usage is that the types must be consistent: if
we pass a string as an argument, then a string must be returned.

However we can add further restrictions on types by using the `extend` keyword,
combined with an interface.

```ts
interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}
```

In this example the `logLength` generic function is limited to types that
implement the `Lengthwise` interface. So: any argument that is passed to
`logLength` and any value that is returned by it must match the shape of
`Lengthwise`, having the `length` property.

## Interfaces and classes

Generics can also be used profitably when working with stricter OOP constructs.

```ts
interface KeyValuePair<K, V> {
  key: K;
  value: V;
}
```

The `KeyValuePair` interface has two generic type parameters: K for the key and
V for the value. The interface defines an object shape that must possess the
properties `key` and `value`, e.g:

```ts
{
  key: 2,
  value: 'something'
}
```

In this form the generic specifies that whatever types are used for the key and
the pair must be used consistently, e.g. this would be wrong:

```ts
{
  key: 'age',
  value: 32
}
```

The following class uses the `KeyValuePair` interface:

```ts
class Storage<K, V> {
  private items: KeyValuePair<K, V>[] = [];

  add(item: KeyValuePair<K, V>): void {
    this.items.push(item);
  }

  getByKey(key: K): V | undefined {
    const foundItem = this.items.find((item) => item.key === key);
    return foundItem ? foundItem.value : undefined;
  }

  getAll(): KeyValuePair<K, V>[] {
    return this.items;
  }
}
```

This class stores objects that match the `KeyValuesPair` interface in an array
and provides and add and list method for accessing/returning them.

The `add` method takes an item of type `KeyValuePair<K, V>` and adds it to the
`items` array. The `getByKey` method takes a key of type `K` and returns the
value of type `V` associated with that key or undefined if the key is not found.
The `getAll` method returns all stored key-value pairs.

Here is an example of instantiating the class:

```ts
const storage = new Storage<number, string>();

storage.add({ key: 1, value: "one" });
storage.add({ key: 2, value: "two" });

const value = storage.getByKey(1);
const allItems = storage.getAll();

console.log(value);
// value: "one"

console.log(allItems);

// allItems: [
//   { key: 1, value: "one" },
//   { key: 2, value: "two" }
// ]
```

## Real examples

### GraphQL client for query and mutation requests over `fetch`

```ts
type GraphQlResult<T> = {
  data: T;
  errors?: Array<{
    message: string;
    locations: Array<{ line: number; column: number }>;
    path: Array<string | number>;
  }>;
};

export class GraphQlClient {
  private endpoint: string;

  constructor(endpoint: string) {
    this.endpoint = endpoint;
  }
  async request<T>(
    query: string,
    variables?: Record<string, unknown>
  ): Promise<T> {
    try {
      const response = await fetch(this.endpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ query, variables }),
      });

      if (!response.ok) {
        throw new Error(
          `Network error: ${response.status} - ${response.statusText}`
        );
      }

      const result: GraphQlResult<T> = await response.json();

      if (result.errors) {
        throw new Error(`GraphQL error: ${JSON.stringify(result.errors)}`);
      }

      return result.data;
    } catch (error) {
      console.error(error);
      throw error;
    }
  }
}
```

### VSCode extension TreeView generator

In VSCode a TreeView is a list of values that may have nested values, like a
directory. The following generic is a helper function that generates a TreeView
based on a given class that is passed in as an argument, along with the class's
constructor values (`args` in the example). It also calls a method `refresh` on
each instance of the class.

```ts
function createTreeView<
  T extends IndexHyperlinksProvider | IndexMetadataProvider,
  U extends LinkTypes | MetadataTypes
>(
  viewType: string,
  ProviderClass: new (...args: any[]) => T,
  type: U,
  activeEditor?: string | undefined,
  ...args: ConstructorParameters<typeof ProviderClass>
): T {
  const view = new ProviderClass(...args, type);
  if (view instanceof IndexHyperlinksProvider) {
    view.refresh(activeEditor, type as LinkTypes);
  } else if (view instanceof IndexMetadataProvider) {
    view.refreshIndex();
  }
  vscode.window.registerTreeDataProvider(viewType, view);
  return view;
}
```


title: Network_card
last_modified: 2024-10-18 19:18:10
body:
# Network card

The network card (technically know as the Network Interface Card (NIC)) or
_network adapter_ is the hardware device that allows a computer to connect to a
network.

They are the physical interface between the computer and the network
[link](./Link_Layer_of_Internet_Protocol.md), e.g. WiFi or ethernet.

They can be internal and built into the [motherboard](./Motherboard.md) or
external as in the case of USB adaptors.

Each network card has a unique [MAC address](./MAC_addresses.md) to identify the
device on the network.

Network cards on consumer-grade devices typically utilise the devices resources
and the kernel manages its actions via a driver. More high-end devices
(typically used in servers) have their own processors and memory.


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: 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: 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: Algorithmic_complexity
last_modified: 2024-10-19 09:56:34
body:
# Algorithmic complexity

![Screenshot_2021-05-11_at_18.55.23.png](Screenshot_2021-05-11_at_18.55.23.png)
_Summary of the main classes of algorithmic complexity_

## Distinguish algorithms from programs

Test commit Algorithms are general sets of instructions that take data in one
state, follow a prescribed series of steps and return data in another state.
Programs are a specific application of one or more algorithms to achieve an
outcome in a specific context. With algorithms, the actual detail of the steps
is mostly abstracted and it is irrelevant to what end the algorithm is being
put. For instance you may create a program that returns addresses from a
database using a postcode. It is irrelevant to the efficiency or value of the
algorithm whether or not you are looking up postcodes or some other form of
alphanumeric string.

## Algorithmic efficiency

Algorithms can be classified based on their efficiency. Efficiency is function
of the runtime speed. However this doesn't always mean that the fastest
algorithms are best.

If we are landing the Curiosity Rover on Mars we may choose an algorithm that is
slower on average for a guarantee that it will never take longer than we find
acceptable. In other cases for example a video game, we may choose an algorithm
that keeps the average time down, even if this occasionally leads to processes
that need to be aborted because they take too long.

We need a generalised measure of efficiency to compare algorithms, across
variant hardware. We can't simply use the number of steps, since some steps will
be quicker to complete than others in the course of the overall algorithm and
may take longer on different machines. Moreover the same algorithm could run at
different speeds on the same machine, depending on its internal state at the
given time that it ran. So we use the following: **the number of steps required
relative to the input.**

> Two given computers may differ in how quickly they can run an algorithm
> depending on clock speed, available memory and so forth. They will however
> tend to require approximately the same number of instructions and we can
> measure the rate at which the number of instructions increases with the
> problem size.

This is what **asymptotic runtime** means: the rate at which the runtime of an
algorithm grows compared to the size of its input. For precision and accuracy we
use the worst case scenario as the benchmark.

So: the efficiency of algorithm _A_ can be judged relative to the efficiency of
algorithm _B_ based on the rate at which the runtime of _A_ grows compared to
its input, compared to the same property in _B_, assuming the worst possible
performance.

From now on we will use the word 'input' to denote the data that the algorithm
receives (in most cases we will envision this as an array containing a certain
data type) and 'execution' to denote the computation that is applied by the
algorithm to each item of the data input. Rephrasing the above with these terms
we can say that 'algorithmic efficiency' is a measure that describes the rate at
which the execution time of an algorithm increases relative to the size of its
input.

We will find that for the runtime of some algorithms, the size of the input does
not change the execution time. In these cases, the runtime is proportional to
the input quantity. In this case, regardless of whether the input is an array of
one hundred elements or an array of ten elements, the amount of work that is
executed on each element is the same.

For other cases, this will not hold true. We will find that there is a
relationship between input size and execution time such that the length of the
input affects the amount of work that needs to be performed on each item at
execution.

## Linear time

Let's start with linear time, which is the easiest runtime to grasp.

We need an example to make this tangible and show how an algorithm's runtime
changes compared to the size of its input. Let's take a simple function that
takes a sequence of integers and returns their sum:

```js
function findSum(arr){
	let total = 0;
	for (let i = 0; i < arr.length; i++){
		total = total += arr[i];
	)
	return total
}
```

The input of this function is an array of integers. It returns their sum as the
output. Let's say that it takes 1ms for the function to sum an array of two
integers.

If we passed in an array of four integers, how would this change the runtime?
The answer is that, providing that the time it takes to sum two integers doesn't
change, it would take twice as long.

As the time it takes to execute `findSum` doesn't change, we can say confidently
that the runtime is as long as the number of integers we pass in.

A more general way to say this is that the runtime is equal to size of the
input. For algorithms of the class of which `findSum` is a member: **the total
runtime is proportional to the number of items to be processed**.

## Introducing asymptotic notation

If we say that it takes 1ms for two integers to be summed, this gives us the
following data set:

| Length of input | Runtime |
| :-------------- | ------: |
| 2               |       2 |
| 3               |       3 |
| 4               |       4 |
| 5               |       5 |

If we plotted this as a graph it is clear that this is equivalent to a linear
distribution:![lin.svg](lin.svg)

Algorithms which display this distribution are therefore called **linear
algorithms**.

The crucial point is that the amount of time it takes to sum the integers does
not increase as the algorithm proceeds and the input size grows. This time
remains the same. If it did increase, we would have a fluctuating curve on the
graph. This aspect remains constant, only the instructions increase. This is why
we have a nice steadily-advancing distribution in the graph.

We can now introduce notation to formalise the algorithmic properties we have
been discussing.

## Big O notation

To express linear time algorithms formally, we say that:

> it takes some constant amount of time ($C$) to sum one integer and n times as
> long to sum n integers

Here the constant is the time for each execution to run and n is the length of
the input. Thus the complexity is equal to that time multiplied by the input.

The algebraic expression of this is $cn$ : the constant multiplied by the length
of the input. In algorithmic notation, the reference to the constant is always
removed. Instead we just use n and combine it with a 'big O' which stands for
'order of complexity'. Likewise, if we have an array of four integers being
passed to `findSum` we could technically express it as O(4n), but we don't
because we are interested in the general case not the specific details of the
runtime. So a linear algorithm is expressed algebraically as $O(n)$ which is
read as "oh of n" and means

> $O(n)$ = with an order of complexity equal to (some constant) multiplied by n

Applied, this means an input of length 6 ($n$) where runtime is constant ($c$)
at 1ms has a total runtime of 6 x 1 = 6ms in total. Exactly the same as our
table and graph. O n is just a mathematical way of saying _the runtime grows on
the order of the size of the input._

> It's really important to remember that when we talk about the execution
> runtime being constant at 1ms, this is just an arbitrary placeholder. We are
> not really bothered about whether it's 1ms or 100ms: 'constant' in the
> mathematical sense doesn't mean a unit of time, it means 'unchanging'. We are
> using 1ms to get traction on this concept but the fundamental point being
> expressed is that the size of the input doesn't affect the execution time
> across the length of the execution time.

## Constant time

Constant time is another one of the main classes of algorithmic complexity. It
is expressed as O(1). Here, we do away with n because with constant time we are
only ever dealing with a single execution so we don't need a variable to express
nth in a series or 'more than one'. Constant time covers all singular processes,
without iteration.

An example in practice would be printing `array[0]` . Regardless of the size of
the array, it is only ever going to take one step, or constant times one. On a
graph this is equivalent to a flat line along the time axis. Since it only
happens for one instant, it doesn't persist over time or have multiple
iterations.

### Relation to linear time

If you think about it, there is a clear logical relationship between constant
and linear time: because the execution time of a linear algorithm is constant,
regardless of the size of n, each execution of O(n) is equal to O(1). Thus O(n)
is simply O(1) writ large or iterated. At any given execution of an O(n)
algorithm n is going to be equal to 1.

## Quadratic time

With the examples of constant and linear time, the total number of instructions
doesn't change the amount of work that needs to be performed for each item, but
this only covers one subset of algorithms. In cases other than O(1) and O(n),
the length of the input **can** affect the amount of work that needs to be
performed at execution. The most common example of this scenario is known as
quadratic time, represented as $O(n^2)$.

Let's start with an example.

```js
const letters = ['A', 'B', 'C'];

function quadratic(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length j++) {
      console.log(arr[i]);
    }
  }
}

quadratic(letters);
```

This function takes an array . The outer loop runs once for each element of the
array that is passed to the function. For each iteration of the outer loop, the
inner loop also runs once for each element of the array.

In the example this means that the following is output:

```
A A A B B B C C C (length: 9)
```

Mathematically this means that n (the size of the input) grows at a rate of n2
or the input multiplied by itself. Our outer loop (`i`) is performing n
iterations (just like in linear time) but our inner loop (`j`) is also
performing n iterations, three `j`s for every one `i` . It is performing n
iterations for every nth iteration of the outer loop. So runtime here is
directly proportional to the squared size of the input data set. As the input
array has a length of 3, and the inner array runs once for every element in the
array, this is equal to 3 x 3 or 3 squared (9).

If the input had length 4, the runtime would be 16 or 4x4. For every execution
of linear time (the outer loop) the inner loop runs as many times as is equal to
the length of the input.

This is not a linear algorithm because as n grows the runtime increases as a
factor of it. Therefore the runtime is not growing proportional to the size of
the input, it is growing proportional to the size of the input squared.

Graphically this is represented with a curving lines as follows:
![square.svg](square.svg)

We can clearly see that as n grows, the runtime gets steeper and more
pronounced,

## Logarithmic time (log n)

A logarithm is best understood as the inverse of exponentiation:

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

When we use log in the context of algorithms we are always using the binary
number system so we omit the 2, we just say log.

> With base two logarithms, the logarithm of a number roughly measures the
> number of times you can divide that number by 2 before you get a value that is
> less than or equal to 1

So applying this to the example of $\log 8$ , it is borne out as follows:

- 8 / 2 = 4 — count: 1
- 4 / 2 = 2 — count: 2
- 2 / 2 = 1 — count: 3

As we are now at 1, we can't divide any more, so $\log 8$ is equal to 3.

Obviously this doesn't work so neatly with odd numbers, so we approximate.

For example, with $\log 25$:

- 25 / 2 = 12.5 — count: 1

- 12.5 / 2 = 6.25 — count: 2

- 6.25 / 2 = 3.125 — count: 3

- 3.125 / 2 = 1.5625 — count: 4

- 1.5625 / 2 = 0.78125

  Now we are lower than 1 so we have to stop. We can only say that the answer to
  $\log 25$ is somewhere between 4 and 5.

  The exact answer is $\log 25 \approx 4.64$

Back to algorithms: $O(\log n)$ is a really good complexity to have. It is close
to O(1) and in between O(1) and O(n). Represented graphically, it starts of with
a slight increase in runtime but then quickly levels off:

![Screenshot_2021-05-11_at_18.51.02.png](Screenshot_2021-05-11_at_18.51.02.png)

Many sorting algorithms run in log n time, as does recursion.

## Reducing O complexity to the general case

When we talk about big O we are looking for the most general case, slight
deviations, additions or diminutions in n are not as important as the big
picture. We are looking for the underlying logic and patterns that are
summarised by the classes of O(1), O(n), O(n2) and others.

For example, with the following function:

```js
function sumAndAddTwo(arr) {
  let total = 0;
  for (let i = 0; i < arr.length; i++) {
    total += arr[i];
  }
  total = total += 2;
}
```

The formal representation of the above complexity would be O(n) + O(1). But it's
easier just to say O(n), since the O(1) that comes from adding two to the result
of the loop, makes a marginal difference overall.

Similarly, with the following function:

```js
function processSomeIntegers(integers){
	let sum, product = 0;

	integers.forEach(function(int){
		return sum += int;
	}

	integers.forEach(function(int){
		return product *= int;
	}

	console.log(`The sum is ${sum} and the product is ${product}`);
}
```

It might appear to be more complex than the earlier summing function but it
isn't really. We have one array (`integers` ) and two loops. Each loop is of
O(n) complexity and does a constant amount of work. If we add O(n) and O(n) we
still have O(n), not O(2n). The constant isn't changed in any way by the fact
that we are looping twice through the array in separate processes, it just
doubles the length of n. So rather than formalising this as O(n) + O(n), we just
reduce it to O(n).

When seeking to simplify algorithms to their most general level of complexity,
we should keep in mind the following shorthands:

- Arithmetic operations always take constant time
- Variable assignment always takes constant time
- Accessing an element in an array by index or an object value by key is always
  constant
- in a loop the complexity is the length of the loop times the complexity of
  whatever happens inside of the loop

With this in mind we can break down the `findSum` function like so:

![breakdown.svg](breakdown.svg)

This gives us:

$$ O(1) + O(1) + O(n) $$

Which, as noted above can just be reduced to O(n).

## Space complexity

So far we have talked about time complexity only: how the runtime changes
relative to the size of the input. With space complexity, we are interested in
how much memory (conceived as an abstract spatial quantity corresponding to the
machine's hardware) is required by the algorithm. We can use Big O notation for
space complexity as well as time complexity.

Space complexity in this sense is called 'auxiliary space complexity'. This
means the space that the algorithm itself takes up, independent of the the size
of the inputs. We are not focusing on the space that each input item takes up,
only the overall space of the algorithm.

Again there are some rules of thumb:

- Booleans, `undefined`, and `null` take up constant space
- Strings require O(n) space, where n is the sting length
- Reference types take up O(n): an array of length 4 takes up twice as much
  space as an array of length 2

So with space complexity we are not really interested in how many times the
function executes, if it is a loop. We are looking to where data is stored: how
many variables are initialised, how many items there are in the array.


title: Naming_conventions
last_modified: 2024-10-18 18:55:56
body:
# Python naming conventions

## Underscores

To name a variable or method with multiple words we use underscores to separate
each word.

```python
an_int = 32
print(an_integer.is_integer) # true
```

## Constants

There are no constants in Python. However there a pseudo-constants established
by convention. To denote that a variable should not change you use `UPPER_CASE`.


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

**What is torrenting? Is this the same thing as a peer-to-peer network? How do
these technologies fit within the client-server paradigm?**

Torrenting is a specific application of
[peer_to_peer_networking](Peer_to_peer_network.md) applied to file-sharing.

Each peer on the network both consumes resources and makes resources available
to others.

## Procedure

Large files are divided into small equal sized pieces and each piece is assigned
a unique hash identifier. The `.torrent` file details the number of pieces,
their sizes and hash values.

Clients request different pieces from different peers simultaneously. As pieces
are received, they are verified against their hash. Corrupted or incorrect
pieces are discarded and re-downloaded.

The client software reassembles the pieces in the correct order and the final
file will be identical to the original which can be verified by comparing
hashes.

## Key terms

- _tracker_
  - a server that coordinates communication between peers (so there is a server
    but its role is more lightweight than client-server, coordinating the peers
    rather than hosting or distributing file content)
- _swarm_
  - a group of peers sharing the same file
- _seeding_
  - uploading file pieces to other peers
- _leeching_
  - downloading file pieces from other peers

> An alternative to a tracker server is to use trackerless methods such as
> distributed hash tables

## Terminological clarification

- _BitTorrent_ is the communications [protocols](Network_protocols.md) for P2P
  file sharing. It was also a client software developed by the company
  BitTorrent Inc.

- _torrenting_ is the general terms for that act of sharing files using the
  BitTorrent protocol

## Napster

Napster pre-dated the emergence of the BitTorrent protocol. It did not segment
files and files were downloaded directly from peers. It was a centralised P2P
network because there was a central server that indexed all available files
which kept a database of all connected users and their files.

When you searched Napster you would be querying this DB on the server. The
server would facilitate a direct connection between the consumer and provider
peer for the data exchange.

When users share with BitTorrent the `.torrent` file is the source of truth and
a swarm is created around the users who have possess the file.


title: Disjunction_Elimination
last_modified: 2024-10-18 18:55:56
body:
# Disjunction Elimination

This rule is sometimes also referred to as _Constructive Dilemma_. This can be a
bit tricky to understand because the goal is to derive or _introduce_ a new
proposition separate from the disjunction you start out with. This may be
disjunction, a single proposition or a proposition containing any other logical
connective. You do this by constructing two sub-proofs, one for each of the
disjuncts comprising the disjunction you start out with. If you can derive your
target proposition as the conclusion of each subproof then you may invoke the
conclusion in the main proof and take it to be derived.

![](/img/disjunc-elim.png)

_Here is an example where Disjunction Elimination is used to derive a new
disjunction._

![](/img/proofs-drawio-Page-6.drawio.png)

_Here are two further examples that use Disjunction Elimination to derive
singular propositions_

![](/img/ORelim1.png) ![](/img/ORelim2.png)


title: Accessing_metadata_about_SQL_database
last_modified: 2024-10-18 18:55:56
body:
# Accessing metadata about SQL database

```sql
SHOW DATABASES

SHOW TABLES

-- View column names and data types
DESCRIBE [table_name]

-- View disk usage per column
SHOW TABLE STATUS

```


title: Formatting_output_text_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Formatting output text in Bash

We can use the `-e` flag with `echo` to have greater control over the output of
text. `-e` allows us to use linebreaks, tabs and other formattings within a
string.

## Output text in columns

```bash
echo -e  "Name\t\tNumber"; echo -e "Thomas\t\t123";

Name		Number
Thomas		123
```

## Break text over several lines

```bash
echo -e "This text\nbreaks over\nthree lines"

This text
breaks over
three lines
```

## Colour outputs

![](/img/terminal_colours.png)

```bash
echo -e "\033[31;40mColoured Text\033[0m"
```

The coloured section is prepended by `\033[` and ended with `[0m`. The
foreground colour is given first, and then the background colour.

We can also change the text style. We do this by adding an extra value after the
first square bracket:

```bash
echo -e "\033[4;31;40mColoured Text\033[0m"
```

This underlines the output.

We can create a script that simplifies the construction of colour-formatted
text, e.g

```bash
ulinered="\033[4;31;40m"
red="\033[31;40m"
none="\033[0m"

echo -e $ulinered"ERROR:"$none$red" Something went wrong."$none
```


title: Docker_Compose
last_modified: 2024-10-18 18:55:56
body:
# Docker Compose

- Docker Compose (DC) is a tool for defining and running multi-container
  applications. A typical example would be combining a FE with a BE
  implementation and database as three related but distinct containers.

- DC is a prime example of _infrastructure as code_.

- A YAML file defines all the required configuration and **all services can be
  started with a single command**.

- It provides a consistent configuration accross environments: development,
  test, production

## Composition

Three step process:

1. Define your application image in a Dockerfile
2. Define the services in `docker-compose.yaml` (backend services, networks,
   volumes)
3. Start the entire application with `docker compose up`

### `docker-compose.yml`

- Must always begin with `version`
- Must have `services` map
  - This defines the different components that comprise your application
  - Services can be either an image reference (the one that generates the
    container you want to include) or a build context

Look at the following example. It runs a Python Flask frontend connected to a
Redis key-value pair database for backend.

```yml
# docker-compose.yml

version: "3.9"
services:
  web:
    build: . # here we are using the current directory as the build context
    image: myapp:1.0
    ports:
      - "5050:5000"
    depends_on:
      - redis
  redis:
    image: "redis:alpine"
```

`depends_on` is important - it means this container must be running first before
any others. If this is a DB, it means the data is accessible before the frontend
request start.

## Main commands

```sh
# start the composition:
docker compose up -d

# start a specific service within the composition:
docker compose up -d web
docker compose up -d redis

# view logs for a specific service
docker compose logs --follow web

# view processes by activity
docker compose top
```

## Environment variables

You can define them in the compose file or name them and leave them blank. If
you do this, Docker will look in the host environment for the variable which is
really handy:

```yml
...
services:
  redis:
    ...
    environment:
      ENV1: 'some value'
      ENV2:
```

## See also

[NodeJS and MySQL Docker backend](Node_and_MySQL_db.md)


title: c8173d17_TIMPs
last_modified: 2024-10-25 09:09:15
body:
# c8173d17_TIMPs

After the initial ARPANET was complete, the next major milestone was to enable
access to the network regardless of one's proximity to a host node with an IMP
connection.

The idea was to allow a computer to access resources on another computer
directly without connecting to a host first. This connective computer would
connect to an IMP directly (but still transparently) as a 'dumb terminal' as
with time-sharing and would not be a fully-fledged computing device. These
devices would be called _Terminal_ Information Processors (TIMPs) for this
reason.

The development of TIMPs makes it clearer that the host machines on the ARPANET
were not just connection and transmission nodes for their own purpose, they were
loci for other non-host computers to gain access to an IMP, and thereby, the
broader network. In other words computers would connect to a host which
sustained a connection to an IMP.


title: Capturing_user_input_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Capturing user input in Bash

We use [read](Read_command%20_in_Bash.md) to gather user input.

## Capturing raw inputs

```bash
# Wait for the input
echo "What is your name?"
read name

# Silently gather the input and proceed (the input won't show up in the terminal)
echo "What is your password?"
read -s pass

# Combine in single line
read  -p "What's your favourite animal? " animal

echo name: $name, pass $pass, animal: $animal
```

## Offering a selection

We can use `select` to get the user to choose from a series of options.

```sh
select animal in "bird" "dog" "cow"
do
    echo "You selected $animal"
    break
done
```

This will present each option as number that can be inputted:

```
1) bird
2) dog
3) cow
#? 1
You selected bird
```

We could make this more robust by using a case statement:

```sh
select animal in "bird" "dog" "cow"
do
    case $animal in
        bird) echo "Birds like to tweet";;
        dog) echo "Dogs like to woof";;
        cow) echo "Cows like to moo";;
        quit) break;;
        *) "I'm not sure what that means"
    esac
done
```

## Ensuring you capture a valid response from the user

### Set a default response value with `-i`

If the user doesn't enter anything, the value will be set to the default.

```sh
read -ep "Favourite colour? " -i "blue" favecolour
echo "$favecolour"
# blue
```

Alternative formulation:

```sh

read -p "Favourite colour? [blue]" fave

# If response empty...
if [[ -z $fave ]]; then
    fave="blue"
fi
echo "$fave was selected"
```

### Check right number of arguments supplied

Here we test that the right number of
[arguments](Passing_arguments_and_options_to_Bash_scripts.md)
have been passed to the script:

```sh
if (( $#<3 )); then
    echo "This command requires three arguments:"a
    echo "username, userId, and favouriteNumber"
else
    echo "username: $1"
    echo "userid: $2"
    echo "favourite number: $3"
fi
```

## Check the response is valid

The following example demonstrates checking an input for a pattern (a data-link
integer sequence):

```sh
read -p "Which year? [nnnn] " year
until [[ $year =~ [0-9{4} ]];
    read -p "A four-digit year, please! [nnnn] " year
done
echo "Selected year: $year"

```


title: Python_execution
last_modified: 2024-10-18 18:55:56
body:
# Python execution

For immediately executable scripts, we have to have a Python shebang at the top:

```
#! /usr/local/bin/python3
```

With programs we can just run the `main` file with `python main.py`.


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: 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: Bus
last_modified: 2024-10-18 18:55:56
body:
# Bus

A bus is a communication system that transfers data between components inside a
computer, or between computers.

**A bus can be thought of as a kind of pipeline that allows different components
of the computer to communicate with each other.**

Note that the use of the word "bus" varies somewhat in points of emphasis. A bus
can mean:

- The physical wires that make up the bus
- The communication channel that is established over those wires

## Main buses

| Bus type      | Description                                                                                                                                                                                                        |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| System bus    | The primary pathway between the CPU and [memory](Memory.md). It comprises the **data bus** that transfers data from the memory to the CPU and the **address bus** which transmits requests from the CPU to memory. |
| Internal bus  | Connects local devices for example the harddisk to the CPU.                                                                                                                                                        |
| External bus  | Connects peripheral devices such as disks and printers to the [motherboard](Motherboard.md)                                                                                                                        |
| Expansion bus | Allows expansion boards to access the CPU and memory.                                                                                                                                                              |
| Frontside bus | Main computer bus that determines data transfer rate speed and is the primary data transfer path between the CPU, RAM and other [motherboard](Motherboard.md) devices.                                             |
| Backside bus  | Transfers secondary cache (L2 cache) data at faster speeds, allowing more efficient CPU operations                                                                                                                 |

## Bus standards

### Parallel and serial transmission types

There is a distinction between buses that use **serial** and buses that use
**parallel transmission**. They are distinguished by the way in which the bits
are transferred from one point to another, along the bus.

Serial Transmission is the type of transmission in which a single communication
link is used to transfer the data from an end to another. On other hand Parallel
Transmission is the transmission in which multiple parallel links are used that
transmit each bit of data simultaneously.

<img src="../img/serial-transmission.jpg" width="800px"/>
<img src="../img/parallel-transmission.jpg" width="800px"/>

- Serial buses are cheaper to implement than parallel buses
- Serial buses operate at greater [latency](Bus.md#latency) than parallel buses

## Latency

Latency means _delay_: the delay from the time the data is requested until the
time it arrives. In the context of a microprocesser and buses a key locus of
latency would be between the time a request takes to travel accross the system
bus from the CPU to the memory.

### Bandwidth

In general, bandwidth is a measure of the capacity for a communications channel
to transmit data. A bus is a channel between two components thus we can talk
about the bandwidth of buses. The speed and efficiency of a bus is a function of
its bandwidth, although other factors such as its length and proximity to the
source and receiver are also important.

Bandwidth can be calculated in terms of how many bits can be transferred per
second. The wider the bus, the more bits that can be transferred. If we have a
bus that can run at 66MHz and transfer 64 bits, 64 bits is 8Mb thus the
bandwidth is 8 x 66 = 528Mb.

## Standards

The mode of transmission is used to distinguish the different bus standards.

SCSI (Small Computer System Interface) and ATA (Advanced Technology Attachment)
are used for hard drive devices (i.e. internal buses). USB (Univeral Serial Bus)
and SATA (Serial Advanced Technology Attachment) are used for peripheral
devices, keyboards and modem devices (i.e external buses).


title: Shell_sessions
last_modified: 2024-10-19 09:57:41
body:
# Shell sessions

## **Types of shell session**

Shell sessions can be one of or several instances of the following types:

- **login shell**
  - A session that must be authenticated such as when you access remote
    resources using SSH
- **non-login shell**
  - Not the above
- **interactive shell**
  - A shell session that runs in the terminal and thus that the user can
    _interact_ with
- **non-interactive shell**
  - A shell session that runs without a terminal

If you are working with a remote server you will be in an **interactive login
shell**. If you run a script from the command line you will be in a
**non-interactive non-login shell**.

## Shell sessions and access

The type of shell session that you are currently in affects the
[environmental and shell variables](Environmental-and-shell-variables-04d5ec7e8e2b486a93f002bf686e4bbb)
that you can access. This is because the order in which configuration files are
read on initialisation differs depending on the type of shell.

- a session defined as a non-login shell will read `/etc/bash.bashrc` and then
  the user-specific `~/.bashrc` file to build its environment.
- A session started as a login session will read configuration details from the
  `/etc/profile` file first. It will then look for the first login shell
  configuration file in the user’s home directory to get user-specific
  configuration details.

In Linux, if you want the environmental variable to be accessible from both
login and non-login shells, you must put them in `~/.bashrc`


title: Schema_Definition_Language_in_GraphQL
last_modified: 2024-10-18 18:55:56
body:
# Schema Definition Language

SDL is the formal name for the syntax of GraphQL schemas.

## Types

A schema is a collection of object types that contain fields. Each field has a
type of its own. A field's type can be a primitive/scalar value (such as an
`Int` or a `String`), or it can be another object type (just like a custom type
in TS).

A schema's type can be non-nullable which is to say, a required field. We
indicate this with `!`.

A type for a field can be a collection/array of a given type.

The following example indicates these properties:

```gql
type Person {
  age: Int
  name: String
  pets: [Pet]!
}

type Pet {
  species: String
  name: String
  age: Int
}
```

## Queries

A query is also a schema type but of a special sort.

> The fields of this type are entry points into the rest of the schema. These
> are the top-level fields that the client can query for.

For example if we had this type:

```graphql
type Track {
  id: ID!
    author: Author!
  thumbnail: String
  length: Int
  modulesCount: Int
}
```

We could define a type to access a give `Track` as follows:

```graphql
type Query {
  tracksForHomePage: [Track!]!
}
```

Then use this type as the basis for a query:

```

```

## Descriptions

Descriptions are comments that allow you to document your Schema

Single line:

```gql
"Single line comment"
```

```gql
"""
Multi
line
comment
"""
```


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: Weaving_the_Web_Berners_Lee
last_modified: 2024-11-04 16:42:02
body:
# Weaving the Web (Berners-Lee, 1999)

Tim did not really conceive of the possibility of the centralising and
totalising effects of social media:

_The Web's universality leads to a thriving richness and diversity. If a company
claims to give access to the world of information, then presents a filtered
view, the Web loses its credibility._ (p.143)

_Happily, the Web is so huge that there's no way any one company can dominate
it. All the human effort people and organisations have put in all over the world
to create Web sites and home pages is astoundingly large, and most of the effort
has to do with what's in the Web, not the software used to browse it. The Web's
content, and thus value, will continue despite any one company's actions._
(p.144)

Apropos the "alt-right" etc:

_The analogy of a global brain is tempting, because Web and brain both involve
huge numbers of elements - neurons and Web pages - and a mixture of structure
and apparent randomness. However, a brain has an intelligence that emerges on
quite a different level from anything that a neuron could be aware
of...[W]riters have contemplated an 'emergent property' arising from the mass of
humanity and computers. But remember that such a phenomenon would have its own
agenda. We would not as individuals be ware of it, let alone control it, any
more than the neuron controls the brain._ (p.222)


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: 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: DynamoDB_SDK_commands
last_modified: 2024-10-18 18:55:56
body:
# DynamoDB SDK commands

The following commands are for using `@aws-sdk/client-dynamodb` (the JS SDK).

## Create client

```js
import DynamoDBClient from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({
  region: "eu-west-2",
  accessKeyId: process.env.ACCESS_KEY_ID,
  secretAccessKey: process.env.ACCESS_KEY_ID,
});
```

### DynamoDB Document Client

The Document Client returns the data as a standard JSON document in the manner
of a document-based NoSQL database. Without it, DynamoDB will return the data
with type data which is unwieldy and hard to parse.

To transform into a document structure:

```js
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({
  region: "eu-west-2",
  accessKeyId: process.env.ACCESS_KEY_ID,
  secretAccessKey: process.env.ACCESS_KEY_ID,
});

const dynamoDbDocumentClient = DynamoDBDocumentClient.from(client);
```

## Query a table

Querying is the most performant and cost-effective method since it is an O(1)
lookup against a partition key or secondary index.

```js
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const params = {
  TableName: "YourTableName",
  KeyConditionExpression: "#pk = :pk",
  ExpressionAttributeNames: { "#pk": "PrimaryKeyAttributeName" },
  ExpressionAttributeValues: { ":pk": "PrimaryKeyValue" },
};

const dynamoDbDocumentClient = DynamoDBDocumentClient.from(client);
const data = await dynamoDbDocumentClient.send(new QueryCommand(params));
console.log(data);
```

## Scan a table

Scanning is less performant (O(n)) and most expensive since it requires checking
every item in the database.

```js
import { DynamoDBDocumentClient, ScanCommand } from "@aws-sdk/lib-dynamodb";

const params = {
  TableName: "YourTableName",
};

const dynamoDbDocumentClient = DynamoDBDocumentClient.from(client);
const data = await dynamoDbDocumentClient.send(new ScanCommand(params));
```

## Related notes


title: Three_bit_counter
last_modified: 2024-10-18 18:55:56
body:
# 3-bit Counter

To demonstrate the use of
[Flip-Flops](Flip_flops.md) we will
create the circuit for a 3-bit counter. This simply counts up from 0 to 7
because 7 is the maximum decimal number we can create with three bits ($2^3$):

| Binary | Decimal |
| ------ | ------- |
| 000    | 0       |
| 001    | 1       |
| 010    | 2       |
| 011    | 3       |
| 100    | 4       |
| 101    | 5       |
| 110    | 6       |
| 111    | 7       |

The circuit will have three memory components, each representing one bit of the
3-bit number. When the
[clock pulses](Clock_signals.md), the
3-bit number increments by one. We need to synchronise the operation with a
clock because each bit by itself is meaningless, it only gains meaning by the
relation it sustains to the other two bits hence it must be kept in sync with
them.

We can derive the circuit arrangement by analysing the outputs of a flipflop at
each pulse:

| Combined bits | Q2  | Q1  | Q0  | Decimal |
| ------------- | --- | --- | --- | ------- |
| 000           | 0   | 0   | 0   | 0       |
| 001           | 0   | 0   | 1   | 1       |
| 010           | 0   | 1   | 0   | 2       |
| 011           | 0   | 1   | 1   | 3       |
| 100           | 1   | 0   | 0   | 4       |
| 101           | 1   | 0   | 1   | 5       |
| 110           | 1   | 1   | 0   | 6       |
| 111           | 1   | 1   | 1   | 7       |

If we look at the pattern of each flip-flops' output we notice the following:

- _Q0_ toggles on every pulse
- _Q1_ toggles every time _Q0_ was previously 1
- _Q2_ toggles when both _Q1_ and _Q0_ were previously 1

This means that to construct a circuit that displays this behaviour we just have
to use a
[T flip-flop](Flip_flops.md#t-flip-flops)
since the only state change we need is a single bit toggle three times that
retains its value.

Using these pulse patterns we can construct a circuit as follows:
![](/img/3-bit-adder-diagram.png)

<iframe src="https://circuitverse.org/simulator/embed/3-bit-counter-d33846e3-7538-427d-b4cc-dc64fdaf0af3?theme=default&display_title=false&clock_time=true&fullscreen=true&zoom_in_out=true" style="border-width:; border-style: solid; border-color:;" name="myiframe" id="projectPreview" scrolling="no" frameborder="1" marginheight="0px" marginwidth="0px" height="500" width="600" allowFullScreen></iframe>

<br />

> Remember from the table: Q2 is the most significant bit and Q0 is the least
> significant bit so we should read the output in the interactive circuit
> backwards, reversing the order. Then we will see that the cicuit is cyling
> through 0-7

This is how the circuit works:

- All three flip-flops are connected to the same clock signal so that they are
  synchnonised
- Because _T0_ is connected to the voltage source _Q0_ toggles every time the
  clock pulses
- _T1_ is connected to _Q0_ so a clock pulse causes _Q1_ to toggle only when
  _Q0_ is high in line with the table
- _T2_ is connected to _Q0 AND Q1_ so _Q2_ only toggles on a clock pulse when
  _Q0_ and _Q1_ are both high


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: Cron
last_modified: 2024-10-18 18:55:56
body:
# Cron

## `cronie`

In Arch Linux I use `cronie` for cron jobs. (There is no cron service installed
by default). Install `cronie` and then enable it in systemd with:

```bash
systemctrl enable --now cronie.service
```

## commands

### List cron jobs

```
crontab -l
```

### Open cron file

```
crontab -e
```

### Check cron log

```bash

journalctl | grep CRON
# Different distros have different loggers
```

## Syntax

```bash
m h d mon dow command
# minute, hour, day of month, day of week, bash script/args
# 0-59, 0-23, 1-31, 1-12, 0-6
```

**Examples**

Run on the hour every hour

```
0 * * * * mysqlcheck --all-databases --check-only-changed --silent
```

At 01:42 every day:

```
42 1 * * * mysqlcheck --all-databases --check-only-changed --silent
```

Every half hour:

```
0,30 * * * * ${HOME}/bash_scripts/automate_commit.sh

```

**Shorthands**

- `@reboot` – Run once, at startup
- `@yearly` – Run once a year, “0 0 1 1 \*”.\</>
- `@annually` – same as @yearly
- `@monthly` – Run once a month, “0 0 1 \* \*”
- `@weekly` – Run once a week, “0 0 \* \* 0”
- `@daily` – Run once a day, “0 0 \* \* \*”
- `@midnight` – same as @daily
- `@hourly` – Run once an hour, “0 \* \* \* \*”

**Examples**

```
@hourly mysqlcheck --all-databases --check-only-changed --silent

```

**View the logs**

```bash
sudo grep crontab syslog

```


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: 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: 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: Role_of_memory_in_computation
last_modified: 2024-10-18 18:55:56
body:
# The role of memory in computation

The following steps outline the way in which memory interacts with the processor
during computational cycles, once the [bootstrapping](Boot_process.md) process
has completed and the OS kernel is itself loaded into memory.

1. A file is loaded from the harddisk into memory.
2. The instruction at the first address is sent to the CPU, travelling accross
   the data bus part of the [system bus](Bus.md).
3. The CPU processes this instruction and then sends a request accross the
   address bus part of the system bus for the next instruction to the memory
   controller within the [chipset](Chipset_and_controllers.md).
4. The chipset finds where this instruction is stored within the
   [DRAM](Memory.md#dram) and issues a request to have it read out and send to
   the CPU over the data bus.

> This is a simplified account; it is not the case that only single requests are
> passed back and forth. This would be inefficient and time-wasting. The kernel
> sends to the CPU not just the first instruction in the requested file but also
> a number of instructions that immediately follow it.

![Memory flow diagram](/img/memory-flow.svg)

Every part of the above process - the journey accross the bus, the lookup in the
controller, the operations on the DRAM, the journey back accross the bus - takes
multiple CPU clock cycles.


title: Disk_info
last_modified: 2024-10-18 18:55:56
body:
# Disk info routines

## Current disk capacity

```bash
df -h
```

## Disk last modified

```bash
stat [disk_name]
```


title: Formal_conventions
last_modified: 2024-10-18 19:14:07
body:
# Formal conventions

## Grouping symbols

We use parentheses to delimit the part of an expression we want evaluated first.
If grouping symbols are nested, evaluate the expression in the innermost pair of
grouping symbols first,

## Writing mathematical statements: placement of $=$

We only write one equals sign per line. For example, if we are resolving
parentheses:

$$
\begin{equation} \begin{split} 2 + \[3 + (4+5)\] = 2 + \[3 +9\] \\ = 2 + 12
\\ = 14 \end{split} \end{equation}
$$

We call parentheses (`()`), brackets (`[]`) and braces `{}`) grouping symbols.
When groupings (say parentheses) are used, the expression inside any pair of
parentheses must be evaluated first.


title: Queue
last_modified: 2024-10-18 18:55:56
body:
# Queues

_Visualization of the queue data structure_

![queue.svg](queue.svg)

## A queue is a sequential data structure and most similar to a stack

A queue is basically a stack inverted and can be visualised as a line of people
waiting to be served. The person that is first into the queue is served first.
The people who join the queue behind this person will be served after them.

As a result it can be summarised as **'first in, first out'** or FIFO.

Just like a stack it is a sequential data structure without random access. You
cannot access all the elements at one instant, you can only access the oldest
element. If you wish to access the newest element, you have to move through all
the others that are ahead of it first, at which point it becomes the oldest.

It differs from a stack in that a stack only has one point of transaction: the
front or 'top' of the stack. With a stack you add and remove from the top or
front. With a queue, you have two points of transaction: the front of the queue
for removing elements and the back of the queue for adding elements.

We can however add a 'peek' method to see which is the next element in line to
come out.

As we are removing the first element added, we use an `array shift` method to
remove items from the front of the array.

Removing an element from the queue is called **dequeuing**. Adding an element to
the queue is called **enqueuing**. In terms of the tail/head nomenclature, the
end of the queue where elements are enqueued is the **tail** and front of the
queue, where elements are removed is the **head**.

```js
class Queue {
  items = []; // array to store the elements comprising the queue
  enqueue = (element) => this.items.push(element); // add element to back
  dequeue = () => this.items.shift(); // remove element from the front

  // Optional helper methods:
  isEmpty = () => this.items.length === 0; // return true if the queue is empty
  clear = () => (this.items.length = 0); // empty the queue
  size = () => this.items.length; // count elements in queue
  peek = () => (!this.isEmpty() ? this.items[0] : undefined); // check which element is next in line
}
```

## Use cases

- A queue sequences data in the order that it was first received. Thus it is
  most beneficial in scenarios where receipt time is a factor. For example,
  imagine a service whereby tickets go on sale at a certain time for a limited
  period. You may want to prioritise those who sent their payment earliest over
  those who arrived later.
- Serving requests on a single shared resource like a printer or CPU task
  scheduling.


title: Match_statements_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Match statements in Python

> A `match` statement is the equivalent of a switch or case statement in Python

```python
command = input("What are you doing next? ")

match command:
    case "quit":
        print("Goodbye!")
    case "look":
        print("Looking out")
    case "up" | "down":
        print("up or down")
    case _:
        print("The default")

"""
What are you doing next? up
up or down
"""

match command.split():
    case ["go", "left"]:
        print("go left")
    case ["go", ("fast" | "slow")]:
        print("go fast or slow")

point = (3, 3)
match point:
    case (x, y) if x == y:
        print(f"The point is located on the diagonal Y=X at {x}.")
    case (x, y):
        print(f"Point is not on the diagonal.")
"""
The point is located on the diagonal Y=X at 3.
"""
```


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: Signed_magnitude_representation
last_modified: 2024-10-18 18:55:56
body:
# Signed magnitude representation

## Summary

## Detail

The concept behind SMR is similar to how we designate positive and negative
integers in denary mathematics: we use a dedicated symbol (`-`) to signpost that
the integer is negative. In the binary application the dedicated symbol is one
of the binary digits that comprise the number.

Typically `0` is used to indicate an unsigned (positive) integer and `1` to
indicate a signed (negative) number. The rest of the bits are the magnitude (the
actual numerical value).

We can demonstrate with an 8-bit binary system, encoding `5`: `0000 0101`. Here
the furthest bit (aka. the "most significant bit" (MSB)) at the $2^8$ position
is `0`, designating that the number is unsigned. The signed equivalent is
`1000 0101`, with the MSB being `1` designating the number as signed. When we
are working with signed numbers, the MSB is known as the **signed bit**.

### Advantages

### Limitations

## Applications

## Related notes

[[Signed_and_unsigned_numbers|signed_and_unsigned_numbers]]


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: 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: Git_rebasing
last_modified: 2024-10-18 18:55:56
body:
# Rebasing

Rebasing is a way to integrate changes from one branch into another. In this
regarding it is like merging a branch B into another branch A. However rebasing
differs from normal merging in the way in which it modifies the Git history.

In a normal merge of branch B into branch A, Git creates a new commit that
combines the changes of branches B and A. This is known as the merge commit and
is evident from the following automatic commit message that is generated:

```
Merge branch B of github.com:thomasabishop/remote-repository into A
```

![](/img/normal-merge-again.svg)

In this scenario the merge commit has two or more parent commits each
representing the history of the merged branches. The resulting history of A will
include the commits of B. Basically the two histories are combined.

This would give us a history that looks like the following, with different
colours for the separate SHAs of each merged branch:

![](/img/combined-merge-hist.svg)

If we were to create a rebase branch of A from B, there would be a new singular
history without distinguishing multiple parents that combines the commits of A
and B. The rebased branch's commits are recreated with new commit IDs and new
timestamps, based on the current state of the branch that you are rebasing onto.
This is obviously potentially destructive because it does not preserve the
respective branch's separate history. It rewrites history as a continuous stream
of commits in a single branch.

When a rebase is applied, it will put the diverging B commits at the tip of A
like so:

![](/img/rebase-tip-chage.svg)

And then rebrand the previous A commits to be continuous with B presenting a
flat and linear Git history like the following:

![](/img/single-git-history-rebase.svg)

## Benefits, use-cases

> The purpose of rebasing is to ensure that the commit history of a project is
> as linear and simple as possible, by incorporating changes from one branch
> into another, as if the changes had been made on the other branch all along.

A common use-case is with feature branches as it makes the features fit more
seamlessly with the `main` or `develop` branch.

It is also a technique that can be used to integrate recent commits without
merging.

When to use one over the other:

- **Merge** to allow commits to stand out or to be clearly grouped
- **Merge** to bring large feature branches back into main
- **Rebase** to add minor commits in a main branch into a feature branch
- **Rebase** when you need to move commits from one branch to another

So in terms of my personal workflow, I should be using

- Merge when I want to bring a feature into develop
- Merge when I want to bring develop into main for a release
- Merge any time the feature branch is already public and being used by others.
- Rebase to capture small changes in the parent branch
- Rebase when I have branched from a branch because a refactor or something has
  become more complex than originally anticipated.

## Syntax

For example if we are working on a feature branch off of `main`, we would run
the following from this feature branch:

```
git rebase main
```

This will move the feature branch to the tip of `main`.

If this completes successfully, we would then go on to merge the feature with
main.

If conflicts occur, the rebase will halt. You fix the conflicts and then run:

```
git rebase --continue
```

Or if you don't want to resolve the conflict (not advised):

```
git rebase --skip
```

Or stop the whole process:

```
git rebase --abort
```

### Isolate the point at which one branch diverges from another

This can be useful to check before you create a rebase:

```
git merge-base main feature/some-feature

c33acc84f06fcb94e0e87d9adb240c038da6d71c
```

## Golden rule of rebasing

When we rebase we remove the additional merge commit but we are changing
history. The commits are still there but the SHAs are changed. For this reason
**you should not rebase a public branch**, otherwise you will mess up your
collaborators history. You should do your rebasing locally and then make a pull
request.

## Difference from cherry-picking

The main difference between the two approaches is that
[cherry-picking](Cherry_picking_a_branch.md) is a more selective
process, where you can pick and choose specific commits that you want to include
in another branch. This can be useful when you only want to apply specific
changes or fixes from one branch to another, without including all the changes
made in the original branch.

On the other hand, rebasing is a more comprehensive process that can include all
the changes from one branch to another, but it modifies the commit history,
making it more linear and easier to understand. Unlike rebasing, cherry-picking
does not modify the commit history of either branch.

## Squashing commits

This is a handy feature of rebasing. It allows you to combine multiple commits
into one. This is useful when you have been doing a lot of trial and error to
resolve a bug and you have lots of small commits that are not that important in
themselves.

We use the interactive rebase tool for this.

Checkout the branch where the commit you want to squash is located.

Then run:

```
git rebase -i HEAD~n
```

Where `n` is the number of commits you want to squash starting from the most
recent. This will open an interactive rebase window, listing the commits. You
can then use the keywords to decide what you want to do with them. In our case
this will be `s` for squash.

![](/img/git-interactive-rebase.png)

### Example

I made a small fix commit because something went wrong during build. I do not
want this commit to be in the history because it is so minor. Instead I want to
incorporate these changes into the last public commit.

Trivial commit is `xy` Previous commit is `aa`

```
git rebase -i HEAD~2
```

This displays:

```
pick xy
pick aa
```

Change this to:

```
pick xy
squash aa
```

Now `xy == aa`

### Another example

Here we will rebase the interim commits into the last feature commit

```sh
git rebase -i HEAD~10
```

```
pick a691a7667 feature (shared-nav) add active app check
pick 74a07fdb1 interim: add logging
pick 9af4e2652 interim: more logging
pick 51b36f667 interim: use href not origin
pick 33f161198 interim : try catch handler
pick 41c144ddf interim: remove didLoadCheck
pick ebd1c9f24 interim: fix flash star
pick 77af452e7 interim: rm redundant active app check
pick 79a9b737a iterim: test ternary
pick a90d23223 interim: further tidying
```

```
pick a691a7667 feature (shared-nav) add active app check
squash 74a07fdb1 interim: add logging
squash 9af4e2652 interim: more logging
squash 51b36f667 interim: use href not origin
squash 33f161198 interim : try catch handler
squash 41c144ddf interim: remove didLoadCheck
squash ebd1c9f24 interim: fix flash star
squash 77af452e7 interim: rm redundant active app check
squash 79a9b737a iterim: test ternary
squash a90d23223 interim: further tidying
```

## `git pull rebase`

We can use this command to combine a rebase with a pull. This way we silently
update our local version of a branch with the remote, without adding a merge
commit.

```
git pull --rebase
```

Add `--rebase=preserve` to keep merges that have been done _locally_. It is
generally a good idea to do this.


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: 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: 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: Reset_to_remote_version
last_modified: 2024-10-18 18:55:56
body:
# Reset to remote version of a branch

The scenario: your local Git history has become corrupted in some way and you
want a clean history based on the current state of the remote. We will
demonstrate with `main`.

```
git fetch origin
git reset --hard origin/main
```


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: Peer_to_peer_network
last_modified: 2024-10-18 18:55:56
body:
# Peer to peer network

A decentralised network model where each participant (peer) acts as both a
client and a server.

Resources are shared directly between peers rather than being coordinated via a
server.

Under a server architecture, multiple requests are made from different hosts for
resources. The server manages this load and is in control of what is being
shared, to whom, and when. With P2P there is no central authority equivalent to
this. Each peer both shares and consumes resources and in this sense is both a
client and a server.

A practical example of this is [torrenting](Torrenting.md) - an applicaton of
P2P technology to file sharing.

## Benefits

- Decentralisation, no central authority, also means no single point of failure.
- Scalable: the network capacity grows with the number of users (contrast
  servers)
- Efficiency: idle resources of peers are put to use
- Improved performance for popular content

## Drawbacks

- Security: potential for malicious peers and content
- Inconsistent availability of resources


title: Prototypical_inheritance
last_modified: 2024-10-18 18:55:56
body:
# Prototypical inheritance

## Object oriented basis of JavaScript and nomenclature

As we know, everything in JS that isn't a primitive (i.e. a primitive data type:
string, number, boolean, null) is an object. Where an object is a data structure
that consists in key:value pairs.

The key is always a string and the value can be: a primitive value, a method
(function within an object), an array, another object etc.

> In other object-oriented languages like C# and Java, **functions are called
> methods** however in JS the term **method** is reserved for function that
> exists as a property of an objects that contains it.

### Lack of classes in JS

In contrast to more advanced object-oriented languages that are compiled (Java,
C#), classes do not really exist in JavaScript. This is due to the
prototype-based nature of JS (as we will see) however class-like functionality
can be achieved through the use of functions.

Remember in JS that functions can be simple code blocks that execute when called
(which is what we mean most of the time by 'function') **or they can be
constructor functions which create generic object types from which specific
token instances can be generated as objects.**

It is through these 'generic object types' that something akin to a class can be
created in JavaScript. (These are sometimes called function-objects )

The following is a good account of the differences between prototypal and
class-based languages:

> JavaScript is a prototype-based language, **meaning object properties and
> methods can be shared through generalized objects that have the ability to be
> cloned and extended**. This is known as **prototypical inheritance** and
> differs from **class inheritance**. Among popular object-oriented programming
> languages, JavaScript is relatively unique, as other prominent languages such
> as PHP, Python, and Java are class-based languages, which instead **define
> classes as blueprints for objects**.

### Example of a constructor function

In order to understand prototypes in a moment, it will be helpful to have an
example of a constructor function that can be used to generate object instances:

```jsx
/* Create constructor function: */
function Band(mainAlbum, subgenre) {
  // use Pascal for constructor function names
  this.mainAlbum = mainAlbum;
  this.subgenre = subgenre;
}

/* Then to create an object instance: */

var slayer = new Band("Reign in Blood", "thrash metal");
```

## Prototypes

Now that we know class-type functionality enters JS via constructor functions
and we have an example, we can look at prototypes.

> Prototypes are a special type of object that exist as a property within
> function-objects.

Whenever we create an instance-object from constructor function using `new`, the
object is given a property with the key `_proto_` . It's value is the
`[[prototype]]` property of the function that created, i.e the class of which
the object is an instance:

```jsx
{
  _proto_: prototype;
}
```

Note that we use the syntax `[[prototype]]` to indicate that **whilst the value
exists, it is not accessible via JavaScript code**, in the manner of a normal
object-literal or function-object, because it is the lower-level foundation of
first-order JS code.

So how would this work for the `slayer` object we created above?

```jsx
Slayer._proto_ === Band.prototype;
```

The thing is, you do not tend to see this prototype functionality and it is not
possible to refer to it as a key:value directly. This is because it is something
under-the-hood - it is a process that makes the object-oriented aspects of JS
possible but it is not apparent on the first-order level of everyday coding.

The prototype is like a hidden hook that facilitates the generation of objects
from class-like constructor functions. With our new awareness of it, we are in a
position _to understand how JavaScript works in foundational terms._

## Every non-primitive data type in JS possesses the `Object` prototype

The title above indicates how and why JavaScript establishes its object-oriented
data structure.

When we create an object literal (i.e an every day object not a class-like
function), under-the-hood JS is making a `new Object()` call in much the same
way as we are calling the function-object `Band` when we declare
`var slayer = new Band(...)` .

All instance-objects in JavaScript (which, remember is the set of everything
that is not a primitive) **inherit from the `Object` keyword**. And, to do this,
prototypes are necessary. Now we see how integral prototypes are to JavaScript.

### Examples

Here we create an object-literal and uncover how it has it's basis in the
overall `Object` constructor.

```jsx
var slayerMembers = {
  bassist: "Tom Araya",
  guitarist: "Kerry King",
  guitarist: "Jeff Hanneman",
  drummer: "Dave Lombardo",
};

//  slayerMembers._proto_ === Object.prototype
```

Here we create an instance-object off of our `Band` constructor function and
trace it back to `Object`

```jsx
var deicide = new Band("Legion", "death metal");

/* deicide object relies on Band prototype:
		
		deicide._proto_=== Band.prototype

Band prototype in turn relies in turn on Object prototype: 

 Band.prototype._proto_=== Object.prototype

*/
```

As the above examples show, ultimately all objects in JavaScript (whether
variables, arrays, methods, or functions) eventually lead back to
`Object.prototype` .

### How the browser uses prototypes when interpreting code

When the browser interprets your code attempting to access a property or method
of an object it runs through the following process:

1. Search on the object itself. If fails →
2. Search the object's prototype. If fails →
3. Search the prototype of the linked object. If fails→
4. Keep going until `Object.prototype` is reached

Clearly with each step we are going to a lower level of abstraction, drawing the
curtain back more and more until we got the point where JavaScript effectively
stops because any lower would take you into its lower-level parent language
(C/C++ depending on how the specific browser executes ECMAScript)

Note (3) is basically the prototype of the component itself. So if you started
at (1) with a custom array. At (3) the browser would be querying
`Array.prototype` i.e the basic foundational array object.

This explains why the full-name of certain methods on the global objects,
includes reference to 'prototype', for instance:

- `toFixed` → `Number.prototype.toFixed()`
- `.trim` → `String.prototype.trim()`.

### Using the function-object of `Object` to create an object literal

As a side-effect of uncovering the prototypical basis of `Object()` we can use
it to create an object literal in another way.

Standardly to create a new, empty object literal we would use:

```jsx
var slayerMembers = {...}
```

But now we could just as easily direct the code to `Object()` prototype and
achieve the same outcome:

```jsx
let slayerMembers = new Object();
```

### Finding the `[[Prototype]]` of a JS object with `getPrototypeOf()`

We can find out the `[[prototype]]` of a given object in JavaScript with a
special method applied to the object in question. The method we use is one of
the inherent methods that belong to the `Object()` constructor function:
`getPrototypeOf()` .

Here is an example:

```jsx
console.log(Object.getPrototypeOf(slayer));

/*

Returns: 

Object {constructor: , __defineGetter__: ,
 __defineSetter__: , hasOwnProperty: , __lookupGetter__: , …}

*/
```

We could also use the following approach to get the same output however this is
not recommended for production:

```jsx
console.log(slayer.__prototype__);
```

The output we get when querying the prototype is the same in each instance.

## But why bother using prototypes in your code?

It is informative to learn how prototypes are behind the object behaviour we
observe at a high level in JavaScript and to know that there is a common,
lower-level root but when would you actually need to use prototype methods?

The reason is mainly to do with performance and optimisation

> When we create a `deicide` and `slayer` object using the constructor function
> `Band()` JS creates two _copies_ of the constructor function, one for each
> generated object. This means there are two instances of `mainAlbum` for each
> object even though each do exactly the same thing. This wastes memory and
> performance time every time the script runs.

As a prototype object is an object, we can attach properties and methods to the
prototype object. Thus, enabling all the objects created using the constructor
function to share those properties and methods. However, the beauty is that the
method is applied to the prototype, so it is only stored in the memory once, but
every instance of the object has access to it.

```jsx
/* So say I wanted to add an age property to the Band()constructor that all objects of this type have access to. I could do this without wasting memory and without the need to change the original constructor function by referring to the prototype: */

Band.prototype.age = null;

Slayer.age = 25;
```

## Further steps

We are going to stop here for the time being since the primary aim of uncovering
prototypes and understanding how they underly all objects and object methods in
JS has been achieved.

However it is important to note that there is more that you can do with
prototypes. The main additional thing is using the prototypical basis of
constructor functions (i.e pseudo-classes) to add and remove key value pairs in
the resulting objects. This is useful when you want to create behaviour that is
much more like classes in compiled OOP languages.


title: Distributivity
last_modified: 2024-10-18 18:55:56
body:
# The Distributive Property of Multiplication

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

$$ a \cdot (b + c) = a \cdot b + a \cdot c $$

### Demonstration

When faced with $4(2\cdot3)$ we may proceed with the official order of
operations in algebra, namely:

```
4 x (2 + 3) = 4 x (5)
= 20
```

In other words we find the sum of the values in parentheses and then multiply
this by the value outside of the brackets.

When we use distributive property we _distribute_ each value in the parentheses
against the value outside of the parentheses:

```
4 x (2 + 3) = (4 x 2) + (4 x 3)
8 + 12 = 20
```


title: Axioms_of_set_theory
last_modified: 2024-10-18 19:10:26
body:
# Axioms of set theory

The basic notions of set theory are defined in
[Basic properties of sets](Basic%20properties%20of%20sets.md). There we
introduced a formal syntax that will be utilised to define the axioms. For easy
reference:

- variables $a,b,c,...$ to range over sets
- variables $x,y,z$ to range over ordinary objects as well as sets.

## Axiom of Extensionality

Sets which contain the same members are the same set. If sets A and B contain
the same elements then A = B.
$$\forall a \forall b [\forall x (x \in a \longleftrightarrow x \in b) \rightarrow a =b]$$

[link to test](beta.md)


title: Negation_Elimination
last_modified: 2024-10-18 18:55:56
body:
# Negation Elimination

Like the [introduction](Negation_Introduction.md) rule for
negation, the elimination rule also works by deriving a contradiction. It is
basically _Negation Introduction_ in reverse. Instead of starting the sub-proof
with a true proposition from which you derive a contradiction, you start with
the negation of a proposition, derive a contradiction and then assert the
positive of the negated proposition you started out with.

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


title: Logical_possibility_and_necessity
last_modified: 2024-10-18 18:55:56
body:
# Logical possibility and necessity

## Logical possibility

In distinguishing the properties of
[logical consistency](Logical_consistency.md) and
[validity](Validity_and_entailment.md) we make tacit use
of the notion of **possibility**. This is because when we consider the validity
of an argument we are assessing truth-conditions and this consists in asking
ourselves what could or could not be the case: were it such that _P_, then it
would be the case that _Q_. It is important to understand what possibility means
in the context of logic and how it differs from what we might mean ordinarily
when we use the term.

It is evident from the case of arguments that are valid but not sound that logic
operates with a specialised notion of possibility. For example it has to be the
case that the proposition _Every woman can levitate_ is logically possible since
the following argument is valid:

```
1.  P: Janice is a woman.
2.  P: Every woman can levitate.
3.  C: Janice can levitate.
```

But we know of course that women cannot levitate. When we assert that this is
impossible we are relying on a stronger notion of possibility than logical
possibility. It follows that the concept of possibility can have different
degrees. The scope of the concept of possibility has been the concern of
logicians and philosophers since at least the time of Plato and numerous
different formulations exist. The notion that we mostly work with unreflectively
in everyday life is nomological possibility. This means ‘governed by the
application of laws’ where these laws pertain to our current understanding of
the natural world as determined by physics. Levitation is therefore
nomologically impossible but logically possible.

If logical possibility is not constrained by the laws of physics does it place
any restrictions on what is possible? Logic applies a single restriction, the
law of non-contradiction: a proposition cannot both be true and false at once.
The following propositions are examples of a contradictory propositions.

Some examples of contradictions:

- There is a dog that is not a dog
- Today is Tuesday and today is not Tuesday
- The cat that is dead is alive

From this we can derive the following property of logical possibility:

> A proposition is logically possible just if it does not imply a contradiction.

## Logical necessity

A proposition is _logically necessary_ if it is true in every logically possible
circumstance which is to say: true on every possible truth functional
assignment. Necessity and
[logical truth](Logical_truth_and_falsity.md#logical-truth)
are therefore synonyms: anything that is logically true (a tautology) is true by
necessity (could not be otherwise.)

Further, every logical truth is logically possible but not everything that is
logically possible is logically true. It is possible that it is raining but this
is not logically necessary - it could be otherwise, i.e not raining. However it
is not possible that it could be both raining and not raining.


title: Split_into_array_in_Bash
last_modified: 2024-10-18 18:55:56
body:
# Splitting input into an array

## readarray

`readarray` makes it really easy to split input into an array based on new
lines. Say we have this file as input:

```
123
456
789
```

Then we can split like so:

```bash
readarray -t name_for_array < ./input.text

# Print all elements
echo "${name_for_array[@]}"

# Print element by index

echo "${name_for_array[1]}"
456
```

If we want to read a string directly:

```bash
readarray -t new_name_for_array <<< "here
is
some
text"

echo "${new_name_for_array[1]}"
is
```

> The _-t_ flag removes the trailing newline

See more: https://linuxhint.com/split-string-array-bash/

## read

For delimiters other than a space we have to use `read`, combined with `IFS` the
**Internal Field Separator**.

For example, to split by comma:

```plaintext
# comma-input.txt
something,something else,something more
```

```bash
IFS=',' read -a arr < ./comma_inputs.txt
```

> We use the `-a` flag to signal that we want each item read returned as an
> element in an array

## mapfile

We can use `mapfile` to read the lines of a input file in set segments.

For the following file:

```
line one
line two
line three
line four
```

We could generate the following output:

```
-----SNIP-----
line one
line two
-----SNIP-----
line three
line four
```

With:

```bash
while mapfile -t -n 2 ary && ((${#ary[@]})); do
  printf '%s\n' "${ary[@]}"
  printf -- '--- SNIP ---\n'
 done < $testInput
```

So, while there are input lines, map each line into an array and return it in
groups of 2.


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: HTTP_request_types
last_modified: 2024-10-18 19:14:47
body:
# HTTP request types

## GET

- Get data

## POST

- Create data

## PUT

- Update data

## DELETE

- Remove data


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: Clock_signals
last_modified: 2024-10-18 18:55:56
body:
# Clock signals

In the examples of digital circuits so far (i.e
[adders](Half_adder_and_full_adder.md)
and [latches](Latches.md)) everything
happens in a single instant or over several repeated instances. This is because
of how simple the circuits are. In the case of latches only a single bit is
updated. And even with rippled adders they are just a series of 1-bit updaters
in a chain.

With more complex circuits that use multiple memory devices which store a series
of bits at once, we need a way to ensure that the bits are set at the same time.
We do this by sequencing the execution with the pulses of the system clock.

A single iteration of the volatage rising and falling is a **pulse**. A complete
oscillation from low to high and back to low is a **cycle**. As with all
[electromagnetic](Electromagnetism.md)
signals we measure the frequency of the wave in Hertz: cylcles per second. We
also further distinguish the rising and falling edge of a pulse. Rising
represents the signal passing from ground to its maximum voltage and falling is
the reverse (the electrons moving from the voltage source to ground).

The diagram below shows a pulse cycle of 2Hz.

![](/img/clock_pulses.png)

## Linking components to the clock

- All components that need to be synchronised are connected to the clock
- State changes in the component occur only when a clock pulse occurs
- Clock-driven components will typically trigger their state changes on either
  the rising edge or the falling edge of the pulse.
- Components that trigger state changes on the rising pulse are **positive
  edge-triggered**
- Components that trigger state changes on the falling pulse are **negative
  edge-triggered**

The role of the clock is essential in the functioning of the
[CPU](CPU_architecture.md#the-system-clock). It is
the system clock that gives CPUs their performance rating: how many processes
can execute within a given clock cycle.


title: Controlled_components_in_React
last_modified: 2024-10-18 18:55:56
body:
# Controlled components

Controlled components relate to how you use forms in React.

You can use standard form HTML within a React component but applying React state
to the form via controlled components gives you greater power over what you do
with the inputs and how you handle the data that is received.

Standard HTML forms have a separate state from the rest of the document object
and this is highly mutable. It can send requests to a server and reload the
page. This mutability can obviously interfere with the state you maintain in
your React components; this is why it is best to manage form state along with
React state.

We can combine the two [native HTML form state and React state] by making the
React state be the “single source of truth”. Then the React component that
renders a form also controls what happens in that form on subsequent user input.
An input form element whose value is controlled by React in this way is called a
“controlled component”.


title: Git_bisect
last_modified: 2024-10-18 18:55:56
body:
# Bisect

Bisect can be used to identify commits that introduce a bug or regression in our
code.

It is most useful for when we know there is a problem in the code and we know
there was a point in the past where the bug did not exist. We can compare the
two points and try to identify where things went wrong.

We mark the last good revision and the first bad revision. Bisect will the reset
the code to the midpoint between the good and bad versions and let you test it.
You mark that as a good or bad version and then bisect repeats the process.

![](/img/git-bisect.svg)

## Procedure

```
git bisect start

git bisect good <SHA, tag, branch>

git bisect bad <SHA, tag, branch>
```


title: Network_fundamentals
last_modified: 2024-10-18 18:55:56
body:
# Network fundamentals

> A network is a system that allows computing devices to communicate and
> exchange information with each other.

In order for devices to be able to communicate they must share a common
**communication protocol**.

A protocol specifies **rules determining how information is to be exchanged**.
(Simply connecting two devices is not sufficient for them to be able to
communicate, they must have a shared language.)

The nodes of a network are called [hosts](Network_hosts.md).


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: Identify_merged_branches
last_modified: 2024-10-18 18:55:56
body:
# Identify merged branches

```sh
# View merged
git branch --merged

# View merged remote
git branch -r --merged

# View unmerged
git branch --no-merged

# View unmerged remote

git branch -r --no-merged
```

The above cases run the merge check from the point of view of HEAD as this is
the default.

But we can also run it from any branch.

```
git branch --merged non_head_branch
```

## Demonstration

We have the following branches

```
git branch

* main
key_feature
another_feature
```

The branches other than `main`, have not been merged:

```
git branch --merged

* main
```

Just to confirm:

```
git branch --no-merged

key_feature
another_feature
```


title: Process_module_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# The `process` module in Node.js

`process` is a core module and a global object accessible from anywhere in a
Node.js application. It contains functionality that allows us to interact with
information about the current process instance of Node.

For example, we can use it to get environment information, read environment
variables, parse arguments that are passed to the run command, communicate with
the terminal and exit the current process.

## Managing runtime environments

See
[Managing Environments](Managing_environments_in_NodeJS.md).

## Accessing arguments: `process.argv`

We can use `process.argv` to return an array containing the command-line
arguments passed when a Node process is launched. This could be a whole-app
entrypoint (i.e. `index.js`) or a single file we are running.

For instance if we run the following file:

```js
// process-demo.js
console.log(3 + 3);
console.log(process.argv);
```

We get:

```bash
6
[
  '/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node',
  '/Users/thomasbishop/prepos/testNode.js'
]
```

The first item is the last executed process. The second is the array of
arguments.

In the array, the first value is a reference to the Node runtime binary. The
second is the file that was passed to Node.

If we passed in a parameter we would get that too:

```
node process-demo.js --fakeFlag
```

Gives us:

```bash
[
  "/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node",
  "/Users/thomasbishop/prepos/testNode.js",
  "--fake-flag",
]
```

When writing Node CLI applications we can write functions that parse standard
input. For example:

```js
function parseStandardInput(flag) {
  let indexAfterFlag = process.argv.indexOf(flag);
  console.log(process.argv[indexAfterFlag]);
}
```

Say we ran a program that took in a username:

```bash
node userName.js --user Thomas
```

Then `parseStandardInput("--user")` would give us `"thomas"`

## Standard input and output

Below is the most basic use case: writing to the output.

```js
// alpha.js
process.stdout.write("Hello from file \n");
```

```
node alpha.js
Hello from file
```

Typically we want to write and read data that the user provides. To do this we
need to wait on that event. So we use Node's asynchonous
[event listeners](events.md). We wait
on the `data` event:

```js
process.stdin.on("data", (data) => {
  process.stdout.write(data.toString().trim());
});

process.stdout.write("\n What is your name? \n");
process.stdout.write(` \n > `);
```

This waits for whatever input is given and then echoes it.

Currently there is no way to end this process; it will just keep echoing the
input.

So we add an exit clause:

```js
process.stdin.on("data", (data) => {
  process.stdout.write(data.toString().trim());
  process.exit();
});
```

We can also execute functionality on the exit event:

```js
process.on("exit", () => {
  // Do something
});
```

> Timings can also obviously be managed via the `setTimeout` and `setInterval`
> methods.

### Additional useful methods

```js
process.stdout.clearLine();
process.stdout.cursorTo([int]);
```

### `readline`

The core `readline` module simplifies the handling of standard input and output
by providing a wrapper. It reads the input stream line by line. Basic usage:

```js
var readline = require("readline");

var rl = readline.createInterface(process.stdin, process.stdout);

rl.question("What is your age? ", (age) => {
  console.log("Your age is: " + age);
});
```

Usage scenarios at: https://www.geeksforgeeks.org/node-js-readline-module/


title: Conditional_Elimination
last_modified: 2024-10-18 18:55:56
body:
# Conditional elimination

If we have a conditional and we have independently derived its antecedent, we
may invoke its consequent. This is often referred to as _Modus ponens_
(affirming the antecedent).

![](/img/cond-elim.png)


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: Expressing_whole_numbers_as_fractions
last_modified: 2024-10-18 19:13:45
body:
# Expressing whole numbers as fractions

Being asked to express a natural number as a fraction seems confusing at first
but you need to just know that for any whole number $n$, you express it as a
fraction with $\frac{n}{1}$.

_Express 8 as an equivalent fraction having the denominator 5_

$$
8 = \frac{8}{1} = \frac{8 \cdot 5}{1 \cdot 5} = \frac{40}{5}
$$


title: cfbef1c4_web_precursors
last_modified: 2024-10-24 17:28:51
body:
# cfbef1c4_web_precursors

## Early precursors to the commercial internet

Prior to the commercial internet and the advent of the web, there were services
in the 1980s which allowed home computers to connect to limited public networks.
Example services: checking one's bank balance, paying bills, transferring money,
booking holidays.

(Presumably, the services would be hosted on a providers'
[mainframe](Mainframe_computers.md) or mini-computer, which the consumer would
access through something like time-sharing?)

![BT telephone modem](../img/modem-bt.png)

The mechanism of connection was via a modem. A device that connected to your
phone's cradle. Digital signals from your home computer would be converted into
sound signals ("tones") that would travel through the phone transmitter to a
receiver at the service provider which you would "dial-up" beforehand.

In the US the main provider was Micronet in the 1970s, which became Compuserve
in the 1980s and eventually AOL in the 1990s. In the UK there was Prestel
provided by BT, first introduced in 1971.

These services had an expensive subscription model and consequently uptake was
limited.

In addition there were bulletin board systems (BBS), typically administrated by
hobbyists. Their personal computers acted as servers that other users would
dial-up to access. They permitted the sharing of news and messages and later
chat-rooms for realtime communication. Some of the biggest BBSs later became the
first ISPs.


title: Interactive_staging
last_modified: 2024-10-18 18:55:56
body:
# Interactive staging

With interactive staging we can stage sub-portions of files rather than the
whole file. This makes commits much more targetted and atomic.

## Basic use

We enter interactive mode with:

```
git add -i
```

This opens an interface:

![](/img/git-interactive-mode-2.png)

We select 2 and it lets us stage by number. If I enter 1, it will stage the
first change.

If we then go into 3 for revert, we can undo what we have staged.

> Note that untracked files are not automatically added to the changes. We have
> to manually add them with 4 ("add untracked").

> Interactive mode doesn't commit anything, it is only for staging.

## Working with patches and hunks

There's not much utility in interactive mode if you are commiting whole files.
You can just use `git add [file]` and not bother with it.

But it is useful for staging sub-portions of a file, which are called **hunks**.

We access these via **patch mode**:

![](/img/git-patch-mode.png)

### Splitting hunks

Git will try to suggest the best hunks it can but these will sometimes not
reflect the changes you want. Sometimes they will reflect multiple changes
rather than a single change.

So long as there is an unchanged line between the different changes that it has
selected as a hunk you can split the hunk further. You just hit `s` in patch
mode, and it will repeatedly split the hunk each time until you get what you
want.

This is still an automated process and you may not find that the splitting
results in a hunk you want to commit. In this case you can use manual splitting
mode. We enter this with `e`.

This will oped up Vim for the manual work to be done:

![](/img/git-manual-hunk.png)

We use the diff symbols `+`, `-` and space to do this.

### Accessing patch mode directly

If we just want to go straight to patch mode, without anything else:

```
git add -p
```

We can also work with patches in the following commands:

```
git stash -p
git reset -p
git restore -p
git commit -p
```


title: 0716531c_rewilding_the_internet
last_modified: 2024-11-11 15:47:03
body:
# 0716531c_rewilding_the_internet

The following
[analogy](https://www.noemamag.com/we-need-to-rewild-the-internet/) can be
useful in understanding how the internet has become such a negative environment.
How it has transmogrified from its original promise of a humanistic space that
would facilitate the connection of individuals based on shared interests and
values to an environment that is entirely mediated by capital, subject to
control, censorship and the violation of privacy.

In the 18th-century in the northern German states, officials decided to
rationalise the production of timber to enable more systematic extraction.
(Clearly a product of Enlightenment principles of applying reason and science to
agriculture similar to Jethro Tull's invention of the seed drill and the
suspension of three-field rotation to four-field all-round harvesting.)

Instead of a sprawling forest ecosystem that had developed naturally over
hundreds of thousands of years, which allowed for felling without upsetting the
continuance of the system, the forests were stripped and trees were planted in
rows and grids with the arrangement designed to maximise yield and access. This
would be broadly analogous to the factory-farming of chickens compared to
free-range rearing.

For the first cycle it appeared as if this restructuring was a huge success.
Yields were high and the timber was of excellent quality. This was a false dawn,
however. The subsequent yields were a complete failure compared to the past.
Fewer trees grew and those that did had a reduced yield and were subject to
disease. The overall health of the forests declined precipitously.

What explains the initial success? It was made possible by the preceding
centuries of free-range growth and husbandry. The seeming success of the new
system was a product of the generations of investment in the natural ecosystem.
This was exhausted in one cycle of the new regime.

Taking this back to the Web, the analogy is that the web was initially a natural
ecosystem of different communities and technologies developing organically out
of the original open and decentralised protocols. From this diversity emerged a
formidably rich informational space.

Since then, the Web has become highly centralised and homogenised with a tiny
cadre of corporations determining how individuals communicate, share and access
information (Google for search, Android or Apple for phone, Twitter or Facebook
etc.).

The initial fruits of this centralisation (just like the forest 'optimisation')
appeared to be beneficial in the initial 'heyday' of the 2010s when social-media
was new and full of prospect (the political benefits of Twitter and enriched
public sphere, the 'Arab Spring', WikiLeaks etc). But this actually proved to be
a nadir. The vitality on display was a product of the preceding era of the
natural growth of the Web ecosystem.

This decline in quality should be apparent to any reflective user:

- the saturation of advertising to the point where many websites are unusable
- the confection of low-quality content to game 'organic' search rankings
- the surveillance of users across sites and devices to enable the extraction of
  profitable marketing data
- the censorship of political content for the 'violation' of bogus terms of use
  on social media platforms if it does not the serve the broader interests of
  capital and western imperialism
- the saturation of pornography and dehumanising media more generally

This has also involved the reshaping of Internet users themselves, from active
and independent _agents_, to drone-like passive _consumers_ of drivel engineered
to maximise 'engagement' (the monopolisation of attention), where users are like
the viewers of _Infinite Jest_. See, e.g TikTok and its clones.

There are many further points that can be made and ideas that can be
extrapolated from this. Two examples:

- the emergence of supposed 'AI' is going to lead to greater content
  homogenisation and the intensification of informational entropy as the
  technological mechanism consists in feeding the regurgitated content of the
  internet back into itself

- reality itself has become infected by the disease that killed the Web
  (ecocide). The distinction between offline and online is becoming increasingly
  hard to draw (politics - the normalisation and ascendancy of the far right and
  subsequent destabilisation of western states)


title: The_Little_Man_computer
last_modified: 2024-10-19 09:59:33
body:
# The Little Man Computer

The [Little Man Computer]() is a simplified computer that works on Von Neuman
principles. It has all the CPU components we have detailed above. It is
programmed in machine code but for simplicity it uses the denary rather than the
binary number system.

![LMC_5.gif](LMC_5.gif)

On the left is the instruction set. Each number constitutes and execution
routine and the `xx` stand for the address in RAM that the execution will work
on.

Each row of the RAM has a denary address, 1 through to 99. Each address can hold
three digits.

- So the instruction `560` would mean _load the number at address 60._
- The instruction `340` would mean _store a datum at address 40_

### Working through a basic computation

We are going to add two numbers together as a basic example.

1. First we need to place the two numbers in RAM we are going to use `5` and `3`
   - At address `60` we will put the number `5` and at address `61` we will put
     the number `3`
   - We are going to start at address `0` in the top left of the RAM grid
1. The first instruction will be _load address 60_ which in the assembly will be
   `560` . We put this in address `0`, our starting point.
1. This first instruction is now stored in the accumulator.
1. Now we want to _add this number (in the accumulator) to the number in address
   61_
1. This second instruction is `161` . We write this in address `1`
1. Finally we want to store the output of the calculation in the RAM, let's say
   at address `62`
1. So we store the command `362` at address `2`


title: Whole_numbers
last_modified: 2024-10-18 18:55:56
body:
# The set of whole numbers

We recall the set of whole numbers:

$$ \mathbb{W} = {0, 1, 2, 3, ...} $$

# The properties of $\mathbb{W}$

> In mathematics, a **property** is any characteristic that applies to a given
> set.

## The commutative property

### Addition

When **adding** whole numbers, the placement of the addends does not affect the
sum.

Let **a**, **b** represent whole numbers, then:

$$ a + b = b + a $$

### Multiplication

When **multiplying** whole numbers the placement of the
[multiplicands](Symbols-and-formal-conventions-80aeaf1872f94a0d97a2e8d07e3855bd)
does not affect the
[product](Symbols-and-formal-conventions-80aeaf1872f94a0d97a2e8d07e3855bd).

Let **a, b** represent whole numbers, then:

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

### Subtraction

**Subtraction** is not commutative, viz:

$$ a - b \neq b - a $$

### Division

Division is not commutative, viz:

$$ a \div b \neq b \div a $$

## The associative property

### Addition

When grouping symbols (parentheses, brackets, braces) are used with addition,
the particular placement of the grouping symbols relative to each of the addends
does not change the sum.

Let **a**, **b, c** represent whole numbers, then:

$$ (a + b) + c = a + (b + c) $$

### Multiplication

Let **a, b, c** represent whole numbers, then:

$$ a \cdot (b \cdot c) = (a \cdot b) \cdot c $$

### Subtraction

Subtraction is not associative, viz:

$$ (a - b) - c \neq a - (b - c) $$

### Division

Division is not associative

$$ (a \div b) \div c \neq a \div (b \div c) $$

## The property of additive identity

If **a** is any whole number, then:

$$ a + 0 = a $$

We therefore call zero the additive identity: whenever we add zero to a whole
number, the sum is equal to the whole number itself.

## The property of multiplicative identity

If **a** is any whole number, then:

$$ (a \cdot 1 = a) = (1 \cdot a = a) $$

## Multiplication by zero

If **a** is any whole number, then:

$$ (a \cdot 0 = 0) = (0 \cdot a = 0) $$

## Division by zero

Division by zero is **undefined** but zero divided is zero.


title: Middleware_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Middleware

## What is middleware?

- Anything that terminates the `req, res` cycle counts as middleware. It is
  basically anything that acts as an intermediary once the request is received
  but before the resource is sent. A good example would be the
  `app.use(express.json()` or `app.use(bodyParser.json)` functions we call in
  order to be able to parse JSON that is sent from the client.
- You will most likely have multiple middleware functions running at once. We
  call this intermediary part of the cycle the **request processing pipeline**.
- Generally all middleware will be added as a property on the Express `app`
  instance with the `app.use(...)` syntax.

## Creating custom middleware functions

### Basic schema

```js
app.use((req, res, next) => {
  // do some middleware
  next();
});
```

### `next`

The `next` parameter is key, it allows Express to move onto the next middleware
function once the custom middleware executes. Without it, the request processing
pipeline will get blocked.

Middleware functions are basically asynchronous requests and as such they use a
similar syntax as Promises (e.g `then`) for sequencing processes.

### Example of sequence

```js
app.use((req, res, next) => {
  console.log("Do process A...");
  next();
});

app.use((req, res, next) => {
  console.log("Do process B...");
  next();
});
```

> It makes more sense of course to define our middleware within a function and
> then pass it as an argument to `app.use()`

## Including middleware based on environment

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

- Development
- Testing
- Production

We will not want to run certain types of middleware in all environments. For
example, it would be costly to run logging in the app's production environment.
It would make more sense to run this only in development.

### Accessing current Node environment

We can control which middleware we run via the Node envrionment variables:
`process.env` (see for instance [ports](Ports_in_NodeJS.md)).

We could set
[Morgan](Morgan.md) to run
only in development with:

```js
if (app.get("env") === "development") {
  app.use(morgan("common"));
  console.log("Morgan enabled");
}
```


title: NodeJS_scripts
last_modified: 2024-10-18 19:18:42
body:
# NodeJS scripts

If we want to use NodeJS as a scripting language without going to the trouble of
setting up an NPM-based development environment, we can use the following
architecture.

```js
#!/usr/bin/env node

const process = require("process");

const actualScript = (firstParam, secondParam) => {
  // Do something
};

if (require.main === module) {
  const [, param1, param2] = process.argv;
  actualScript(param1, param2).catch(console.error);
}
```

Basically we have a function that contains the main actions of the script. This
is then invoked within `main` in the manner of a Bash or
![Python script](./Single_file_Python_scripts.md)

This obviously requires the Node binary to be in your path and the script must
be run with executable privileges.

If you use any module not in the Node core, you will need to have this installed
globally for it to work. (There are
[ways around this](https://thom4.net/2014/self-contained-node-scripts/) for Node
scripts you publish but for personal scripts this doesn't matter.)

## `require.main`

This construction checks that the script is being directy invoked via the 'node'
command in the terminal rather than called by another module.

This is equivalent to the [following construct]() in Python:

```py
if __name__ == "__main__":
```


title: Connect_to_Mongo_database
last_modified: 2024-10-18 18:55:56
body:
# Connect to a database with Mongoose

Now that we have installed and configured MongoDB, we need to connect to it via
Node.js. Mongoose is a simple API for interacting with a Mongo database via
Node.

With Mongoose installed we can connect to a database. We don't have any Mongo
databases yet beyond the defaults but the following Mongoose connection logic
will create and connect to a new database called `playground`:

Providing the Mongo server is running (execture `mongod`), we will see the
confirmation message in the console.

```js
mongoose
  .connect("mongodb://127.0.0.1/playground")
  .then(() => console.log("Connected to MongoDB"))
  .catch((err) => console.error(err));
```


title: Hardware_abstraction_and_modularity
last_modified: 2024-10-18 18:55:56
body:
# Hardware abstraction and modularity

In computer architecture we deal with complexity by breaking the system into
**modules**. For each module we distinguish **_abstraction_** from
**_implementation_**.

<dl>
  <dt>abstraction</dt>
  <dd>what the module does</dd>
  <dt>implementation</dt>
  <dd>how it does it</dd>
</dl>

When using a module as a building block you are to focus exclusively on the
module's abstraction, ignoring completely its implementation details.

> The abstraction-implementation paradigm helps developers manage complexity and
> maintain sanity: by dividing an overwhelming system into well-defined modules
> we create manageable chunks of implementation work and localize error
> detection and correction.

[N.Nisan, S.Schoken. 2021. **The Elements of Computing Systems** (Second
Edition)]

The design of the diagram below emphasises the role of abstraction and
modularity in the movement from transistors to chips:

![](/img/hardware-abstraction-hierarchy.png)


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: Set_DNS_settings
last_modified: 2024-10-18 18:55:56
body:
# Set DNS settings

## Change the default DNS server

On Arch and most modern Linux distributions domain name resolution is handled
via the `systemd-resolved` #systemd configuration.

Within the system systemd files this will be handled in
`/etc/systemd/network/wired.network` or `/etc/systemd/network/wlan.network`
files etc.

In the file below I have turned of DHCP routing and specified the address of my
Pi-Hole device to handle domain name resolution:

```
#wlan.network

[Match]
Name=wl*

[Link]
RequiredForOnline=routable

[Network]
DHCP=yes
DNS=192.168.0.4
MulticastDNS=yes

[DHCPv4]
UseDNS=no
RouteMetric=600

[IPv6AcceptRA]
RouteMetric=600

```

This stops it using the default DNS server of my router and runs the resolutions
against Pi-Hole.

This should automatically update the two `resolv.conf` files (which should be in
syc), viz:

```
# File: /run/NetworkManager/resolv.conf
# Generated by NetworkManager
nameserver 192.168.0.4
nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

```

```
# File: /etc/resolv.conf
# Generated by NetworkManager
nameserver 192.168.0.4
nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

```

## Related notes

![Network scanning](./Network_scanning.md)
![Network debugging](Network_debugging.md)


title: Application_state_management_with_React_hooks
last_modified: 2024-10-18 18:55:56
body:
# Application state management

Although [React_useReducer](React_useReducer.md) and [React_useContext](React_useContext.md) have
many sound use cases by themselves, when they are combined they offer a way to
acheive a system of global state management, without utilising third-party
libraries like Redux.

## Requirements

The Context API combined with a reducer addresses the following needs:

- be able to consume global state from anywhere in the component hierarchy
  without prop-drilling
- update global state from within child components from anywhere in the
  component hierarchy
- access, maintain and update complex structured data (arrays/objects) not just
  single values, as global state

## Implementation

In essence the approach is as follows:

- Create a context provider that houses the global state object
- Attach this state to a reducer function that operates on the state object
  through dispatch methods

First off, our initial state and overall state object:

```js
const initialState = {
  count: 0,
};
```

Next, we create our context. This is what we will invoke when we want to consume
our state.

```js
export const CounterContext = React.createContext({});
```

Now we need a reducer that will handle the state updates. We will just use the
same setup as we used in the example of
[React_useReducer](React_useReducer.md#refining-the-syntax):

```js
function reducer(state, action) {
  switch (action.type) {
    case "increase":
      return { ...state, counter: state.counter + 1 };
      break;
    case "decrease":
      return { ...state, counter: state.counter - 1 };
      break;
    case "increase_by_payload":
      return { ...state, counter: state.counter + action.payload };
    default:
      throw new Error();
  }
  return newState;
}
```

Finally, we need to make a provider as a top-level component that receives the
reducer's `state` and `dispatch` methods as props:

```js
export const CounterProvider = ({children}) => {
    // We pass our reducer function and initial state to useReducer as params
    const [state, dispatch] = React.useReducer(reducer, initialState)

    // We create our provider and pass the reducer state and update method as props. This is the provider to the CounterContext consumer
    <CounterContext.Provider value={{state, dispatch}}>
        {children}
    </CounterContext.Provider>
}
```

Now whenever we want to consume or update our global state, we can invoke the
context within a lower-level component, for example:

```js
const {state, dispatch} = useContext(CounterContext);

dispatch({
    type 'increase_by_payload',
    payload: 4
})

console.log(state.counter) // 4

```


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

> Awk is a programming language designed for text processing and data
> extraction. It was created in the 1970s and remains widely used today for
> tasks such as filtering and transforming text data, generating reports, and
> performing basic calculations. Awk is known for its simplicity and
> versatility, making it a popular tool for Unix system administrators and data
> analysts.

## Invocation

We can use `awk` directly in `stdin` or we can reference `.awk` files for more
elaborate scripts

```bash
# CLI
awk [program] file1, file2, file3

# Script file
awk -f [ref_to_script_file] file1, file2, file3
```

We can also pipe to it. This piped command receives output from the `echo`
command and prints the value in the last field for each record:

```bash
echo -e "1 2 3 5\n2 2 3 8" | awk '{print $(NF)}'
```

## Syntactic structure

`awk` is a line-oriented language.

An `awk` program consists in a sequence of **pattern: action** statements and
optional functional definitions.

For most of the examples we will use this list as the input:

```
cloud
existence
ministerial
falcon
town
sky
top
bookworm
bookcase
war
Peter 89
Lucia 95
Thomas 76
Marta 67
Joe 92
Alex 78
Sophia 90
Alfred 65
Kate 46
```

> `awk` particularly lends itself to inputs that are structured by whitespace or
> in columns, like what you get from commands like `ls` and `grep`

### Patterns and actions

The basic structure of an `awk` script is as follows:

```
pattern {action}
```

A **pattern** is what you want to match against. It can be a literal string or a
regex. The **action** is what process you want to execute against the lines in
the input that match the pattern.

The following script prints the line that matches `Joe`:

```bash
awk '/Joe/ {print}' list.txt
```

`/Joe/` is the patttern and `{print}` is the action.

### Lines, records, fields

![](/img/awk-outline.png)

When `awk` receives a file it divides the lines into **records**.

Each line `awk` receives is broken up into a sequence of **fields**.

The fields are accessed by special variables:

- `$1` reads the first field, `$2` reads the second field and so on.

- The variable `$0` refers to the whole record

So, in the picture `cloud existence ministerial` corresponse to `$1` `$2` `$3`

## Basic examples

**_Match a pattern_**

```bash
awk '/book/ { print }' list.txt
# bookworm
# bookcase
```

**_Print all words that are longer that five characters_**

```bash
awk 'length($1) > 5 { print $0 }' list.txt
```

For the first field of every line (we only have one field per line), if it is
greater than 5 characters print it. The "every line" part is provided for via
the all fields variable - `$0`.

We actually don't need to include the `{ print $0 }` action, as this is the
default behaviour. We could have just put `length($1) > 5 list.txt`

**_Print all words that do not have three characters_**

```bash
awk '!(length($1) == 3)' list.txt
```

Here we negate by prepending the pattern with `!` and wrapping it in
parentheses.

**_Return words that are either three characters or four characters in length_**

```
awk '(length($1) == 3) || (length($1) == 4)' list.txt
```

Here we use the logical OR to match against more than one pattern. Notice that
whenever we use a Boolean operator such as NOT or OR, we wrap our pattern in
parentheses.

**_Match and string-interpolate the output_**

```bash
awk 'length($1) > 0  {print $1, "has", length($1), "chars"}' list.txt

# storeroom has 9 chars
# tree has 4 chars
# cup has 3 chars
```

**_Match against a numerical property_**

```bash
awk '$2 >= 90 { print $0 }' scores.txt

# Lucia 95
# Joe 92
# Sophia 90
```

This returns the records where there is a secondary numerical field that is
greater than 90.

**_Match a field against a regular expression_**

```bash
awk '$1 ~ /^[b,c]/ {print $1}' words.txt
```

This matches all the fields in the `$1` place that begin with 'b' or 'c'.

The tilde is the regex match operator. You must be passing a regex to use it,
otherwise use `==`.

## Syntactic shorthands

- For a statement like `awk 'length($1) > 5 { print $0 }' list.txt`. We actually
  don't need to include the `{ print $0 }` action, as this is the default
  behaviour and it is implied. We could have just put `length($1) > 5 list.txt`.

https://zetcode.com/lang/awk/

## Built-in variables

### `NF`

The value of `NF` is the **number** of **fields** in the current record. `Awk`
automatically updates the value of `NF` every time it reads a record.

No matter how many fields there are, the last value in a record can always be
represented by `$NF`.

### `NR`

`NR` represents the **number** of **records**. It is set at the point at which
the file is read.

### `FS`

`FS` represents the **field separator**. The default field separator is a space.
We can specify a different separator with the `-F` flag. E.g to separate by
comma:

```bash
awk -F, '{print $1 }' list.txt
```


title: Troubleshooting_MongoDB
last_modified: 2024-10-18 18:55:56
body:
# Troubleshooting MongoDB connection issues

## Arch Linux troubleshooting

Most times any problems will be a result of a Mongo process that is already
running. Resolve with:

```bash
# Kill running Mongo process...
# Identify PID
sudo lsof -iTCP -sTCP:LISTEN -n -P
sudo kill [pid]
```

Otherwise try the below.

```bash
# Check that the systemd service is runnign for Mongo
sudo systemctl status mongodb

# If not, enable and start service (only need to do this once for machine)
sudo systemctl enable --now mongodb
sudo systemctl start --now mongodb

# If issues with Mongo daemon...
# Remove the current socket
rm /tmp/mongodb-27017.sock
```

For additional command line utilities you will also need to install
`mongodb-tools` from the AUR.


title: Network_scanning
last_modified: 2024-10-18 18:55:56
body:
# Network scanning

## List all connected devices on local WiFi network

```sh
arp-scan --interface=wlan0 --localnet
```

## Scan subnet for all connected devices (in case hiding)

```sh
nmap -sn 192.168.0.0/24
```

## Check DNS resolution

```sh
dig google.com
```

Key output:

```
;; Query time: 6 msec
;; SERVER: 192.168.0.4#53(192.168.0.4) (UDP)
;; WHEN: Wed Jun 12 18:27:27 BST 2024
;; MSG SIZE  rcvd: 55
```


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: 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: Multiplexers_and_demultiplexers
last_modified: 2024-10-18 18:55:56
body:
# Multiplexers (MUX) and demultiplexers (DMUX)

## Multiplexer

> Multiplexing is the generic term used to describe the operation of sending one
> or more analogue or digital signals over a common transmission line at
> different times or speeds.

A multiplexer selects one of several input signals and forwards ths selected
input to a single output line.

We have two inputs (A,B) plus a third input SEL (for "select"). Applying a value
to SEL toggles the output between A and B.

![](/img/MUX.png)

Multiplexers can be used to build larger circuits by connecting the output of
one multiplexer to the input of another. They are often used to implement data
selection and switching in digital systems

### Programable gates

One of the main use cases of multiplexers is to implement programmable gates.
These are gates where the logic can be switched. For example an ANDMUXOR gate
uses the SEL value to toggle the operation of a gate between AND and OR for its
two inputs A and B

## Demultiplexer

As the name suggests, a demultiplexer reverses the functionality of a
multiplexer. It receives a single input and based on the selection of the SEL
input it channels it to either an A or a B output.

![](/img/DMUX.png)

We can think of it as a distributor of a value into one of several possible
channels.


title: Update_a_Mongo_document
last_modified: 2024-10-18 18:55:56
body:
# Update a MongoDB document

There are two methods for updating a document

- query first
- update first

## Query first document update

With this approach we first execute a
[query](Querying_a_Mongo_collection.md) to retrieve the document we
want to edit and then make the change. We use the `findById` method to identify
the document by its UUID and then `set` to update specified properties on the
document. The `set` method is one of many operators that can be used to update
values. For example there is also built-in operators for increment, renaming,
multiplying values.

Query first is best used when you want to secure the update with some prior
logic or to validate. For example you may not want to update a course if it is
listed as published. You could use a query to determine the publish status and
then only update the entry if it returns `isPublished: false`.

```js
async function updateCourseFromQuery(id) {
  const course = await Course.findById(id);
  if (!course) return;
  course.set({
    isPublished: true,
    author: "A new author",
  });

  // Instead of an object, we could also set the updated properties individually
  course.isPublished = true;
  course.author = "Biggs Volunksire";

  const result = course.save();
  console.log(result);
}
```

## Update first document update

With this approach we don't bother with a prior query. We are confident that the
update is legitimate and do not need to first determine that certain conditions
are met.

To do this we directly use the `update` method, not `find`:

```js
async function updateCourseFromQuery(id) {
  const result = await Course.update({ _id: id });
  $set: {
    // Invoke the set operator
    author: "Terry Nutile";
    isPublished: true;
  }
  console.log(result);
}
```

This function will just return some metadata about the update. It won't by
default return the updated value. To do this use the `findByIdAndUpdate()`
method instead of `update`:

```js
async function updateCourseFromQuery(id) {
    const course = await Course.findByIdAndUpdate(id, {
    $set: { // Invoke the set operator
        author: 'Terry Nutile'
        isPublished: true
    }, {new: true}});
    console.log(result)
}
```

If we don't add `{new: true}`, it will return the document before the update.

### Updating multiple documents at once

// Add: notes on this


title: Validation_in_NodeJS
last_modified: 2024-10-18 18:55:56
body:
# Creating a RESTful API: Validation

We can provide server-side validation for our projects by using a **schema
validator**. This is a program that declaratively parses the JSON values
received as requests from the client. This makes it easy to systematically
validate the data that we receive from any HTTP requests where the client sends
a body to the endpoint.

One of the most popular schema validators for NodeJS is
[joi](joi).

## Demonstration

Let's say we have a POST request that expects a single field as the body that
must be a string and greater than two characters long. First we define our
schema:

```js
const schema = Joi.object({
  name: Joi.string().min(3).required(),
});

const { error } = schema.validate(req.body);
```

The `schema` variable is an object whose keys should match those of the intended
request body. Instead of actual values we provide Joi's in-built validators,
concatenated as necessary. We then store the results of the validation in a
variable.

Next we add handling in the case of errors:

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

We loop through the error array and return 400s as the response if they are
found. If there are no errors, the Joi object will return `undefined`.


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: 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: 241fe1a3_the_Web_versus_modem_BBSs
last_modified: 2024-11-04 18:33:45
body:
# 241fe1a3_the_Web_versus_modem_BBSs

As access to the Web and the demand for public access grew, services like AOL,
which provided dial-up access to a subset of the broader Internet (along with
email and chat-rooms) became increasingly redundant.

In response to this, they pivoted in their marketing to presenting their service
as a safe, curated means of accessing the information: the Web was confusing, it
was hard to know what was out there and how to find useful information.

By using AOL, you would know which sites to visit for different tasks and which
of these were reputable. They adopted a kind of friendly gatekeeper persona in
the era of unhampered and universal access to information that the Web heralded
and embodied.

(This isn't so strange if we consider that outside of work (and the communities
of computer enthusiasts), personal computers were still relatively new and
computers themselves still rather forbidding entities.)

This function of a gateway to the overwhelming content of the web would be taken
up first by browsers
([Mosaic's](c301a0b3-1d8_Mosaic_Netscape_and_Browser_Wars.md) landing page would
list websites for specific sources of information and user tasks and links to
other directories) and then of course search engines which would allow users to
search for what they needed against an index (usually a subset) of the Web's
total content. (Interestingly in this regard, AOL would eventually buy
Netscape.)

AOL et al made sense when users wanted access to the internet and the web didn't
yet exist. Different networks had different access criteria and were often
poorly signposted, accessible only to those in the know. Private commercial
networks were set up to service typical consumer needs (news, banking, weather
reports etc) but the whole point of the Web as conceived by TBL was to make
everything available to anyone who wanted it through a streamlined and universal
set of protocols.


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: 861cc26e_ARPA_origins
last_modified: 2024-10-24 07:30:17
body:
# 861cc26e_ARPA_origins

After Sputnik, Eisenhower wanted a dedicated, cross-departmental division within
the US government to focus on advanced technological research so that they would
not be caught out again. ARPA was the result.

Originally under the control of the Department of Defence (Pentagon).

Once projects reached maturity, they would be handed over to the armed forces.

It's name switched back and forth between ARPA/DARPA depending on congressional
factors and funding. The switch to DARPA (and the associated re-focusing on
military applications) indirectly precipitated a brain-drain in the late 1970s
which contributed to the birth of the personal computer around the same time.

Main technologies it contributed to or invented include the #ARPANET,
time-sharing and GPS systems.


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: Viewing_remote_changes_without_merging
last_modified: 2024-10-18 18:55:56
body:
# Viewing remote changes without merging

```
git fetch origin/master
git log origin/main
git show origin/master
```


title: Creating_a_Linux_partition_table
last_modified: 2024-10-18 19:12:13
body:
# Creating a Linux partition table

## Creating a partition table

To demonstrate the process of partitioning a harddrive I am going to repartition
an external SATA drive as if it were being primed for a fresh Linux install.

Let's take a look at the disk in its current form:

```
$ fdisk -l

  Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
  Disk model: My Passport 071Aumount /dev/sda2
  Disklabel type: gpt
  Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

  Device      Start       End   Sectors   Size Type
  /dev/sda1      40    409639    409600   200M EFI System
  /dev/sda2  409640 976455639 976046000 465.4G Apple HFS/HFS+
```

(This disk was previously used as a backup disk for MacOS so in addition to the
extended partition which has a proprietary file system type (Apple HFS) it has a
primary partition which would load the recovery OS. In contrast to my main
harddrive this uses the standard SCSI prototcol and thus the partitions are
prepended with `sda`.)

#### 1. Unmount existing partitions

```bash
umount /dev/sda1
umount /dev/sda2
```

#### 2. Deleting the existing partitions

```bash
# Load the disk into fdisk
$ sudo fdisk /dev/sda
Command (m for help): d
Partition number (1,2, default 2): 1
Partition 1 has been deleted.
Command (m for help): d
Selected partition 2
Partition 2 has been deleted.

# Verify deletion with p(rint) command
Command (m for help): p
Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
Disk model: My Passport 071A
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

# Write the changes to disk with w(rite)
w

# Check execution:
$ lsblk

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0 465.7G  0 disk
```

So now the disk has no partitions, just the physical disk space and no
mountpoints. We are ready to re-partition.

#### 3. Re-partition the disk

We are going to create a GPT partition table

```bash
$ sudo fdisk /dev/sda
Command (m for help): g
Created a new GPT disklabel (GUID: E316B1A9-6F73-FB41-8CBB-FA4E3C448F2B).

Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-976717790, default 2048):

# Just press enter here

# The last sector is where we put the actual size we want for the partition
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-976717790, default 976715775): +100G
Created a new partition 1 of type 'Linux filesystem' and of size 100 GiB.

# For the second and final partition, we follow the same steps but don't add a partition size, since it will default to what is left.

Command (m for help): n
Partition number (2-128, default 2):
First sector (209717248-976717790, default 209717248):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (209717248-976717790, default 976715775):

Created a new partition 2 of type 'Linux filesystem' and of size 365.7 GiB.

# Check the partitions with p(rint)
Command (m for help): p
Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
Disk model: My Passport 071A
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 92739978-F7D2-5042-9758-C1429B5C8E11

Device         Start       End   Sectors   Size Type
/dev/sda1       2048 209717247 209715200   100G Linux filesystem
/dev/sda2  209717248 976715775 766998528 365.7G Linux filesystem

# Then write with w
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

We can now confirm our new partitions:

```bash
$ lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0 465.7G  0 disk
├─sda1        8:1    0   100G  0 part
└─sda2        8:2    0 365.7G  0 part
```

#### Naming a partition

By default each partition will have its GUID as its name, but you can add a
human friendly name with:

```bash
sudo e2label /dev/sda1 my_human_name
```

> Whilst we have created our partitions we cannot yet mount them. This is
> because we have not yet set up a filesystem on the partitions. This is the
> next step.

## Related notes

![Linux disk partitions](./Linux_disk_partitions.md)


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: Latches
last_modified: 2024-10-18 18:55:56
body:
# Latches

The **combinatorial digital circuits** we have looked at so far have been
non-sequential. The outcome is a function of its immediate set of inputs and
everything happens at once: there is no means of storing state for future use.
In other words there is no _[memory](Memory.md)_.

In contrast, the output of a **sequential digital circuit** depends not only on
its present set of inputs but also on past inputs to the circuit. It has some
knowledge of its own previous state through the existence of memory. This can be
implemented via components that allow for the **storage and retrieval of binary
data**.

## What is a latch?

A latch is a circuit component that wor

The **SR Latch** (for "set/reset") has two inputs: _S_ (for "set") and _R_ (for
"reset") and one output, _Q_. _Q_ stands for the bit that is remembered. (There
is also _not-Q_ which is the opposite of whatever _Q_ is currently set to.)

The SR Latch goes through the following state changes:

- When _S_ is set to 1, output _Q_ becomes 1 also
- When _S_ goes to 0, _Q_ remains 1
- When _R_ is set to 1, the memory bit is cleared and _Q_ becomes 0.
- _Q_ remains at 0 even if _R_ goes back to 0

This is represented more clearly in the table below:

| S   | R   | Q   | Operation     |
| --- | --- | --- | ------------- |
| 1   | 1   | X   | Invalid, null |

The most succinct account of a latch:

> A latch is a 1-bit memory device that has a state _Q_ of either 1 or 0. The
> _S_ input sets _Q_ to 1 and the _R_ input resets _Q_ to 0.

_The representation of an SR Latch in a digital circuit diagram_:

![](/img/sr_latch_diagram.png)

## Creating a latch circuit

The circuit diagram latch symbol obviously encapsulates more complex
functionality that occurs at the sub-circuit level. We will demonstrate how this
functionality can be achieved with two
[NOR](Logic_gates.md#nor-gate) gates.

The two gates are in a **cross-coupled configuration**. This basically means
that the wires are crossed back on themselves such that the output of one is
also an input of the other at a single stage in the sequence.

The circuit is created as follows:

![](/img/sr_latch_logic_circuit.png)

Interactive version:

<iframe src="https://circuitverse.org/simulator/embed/nor-latch-0869192c-7d7b-4161-b13f-3f72c1bce8e9" 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>

<br />
Let's talk through the logic at each state change:

- When _S_ is set to 1, output _Q_ becomes 1 also
  - N1 is receiving 1 from S and 0 from R by way of N2. This is the inversion of
    OR so TF equals F. Thus N1 is outputting 0.
  - Thus N2 is receiving 0 from N1 as its top input and 0 from R as its bottom
    input. It is therefore outputting 1 because with NOR, FF equals T. For this
    reason, _Q_ is 1 because is directly connected to _R_.
- When _S_ goes to 0, _Q_ remains 1
  - N2 is receiving 0 from N1 as the top input and 0 from R as the bottom input
    hence the overall input is FF which means N2 is outputting T and Q remains 1
  - N1 is outputting 0 because it is receiving 0 as its top input and 1 from its
    bottom input
- When _R_ is set to 1, the memory bit is cleared and _Q_ becomes 0.
  - N2 is receiving 1 from R as its bottom input and 1 from the output of N1 as
    its top input. Therefore it is outputting TT which in NOR evaluates to F
    hence Q is 0
  - N1 is outputting 1 because it is receiving 0 from S as its top input and 0
    from its bottom input coming from N2. FF equals T in NOR therefore 1 is
    outputting 1
- _Q_ remains at 0 even if _R_ goes back to 0
  - N2 is receiving 0 as its bottom input from R and 1 as its top input from N1.
    TF equals F in NOR hence the output of N2 is 0 and Q remains 0
  - N1 is outputting 1 because it is receiving 0 as its top input from S and 0
    as its bottom input from N2. FF equals T in NOR hence N1 is 1


title: Conjunction_Elimination
last_modified: 2024-10-18 18:55:56
body:
# Conditional Elimination

If a conjunction exists, it means that both conjuncts are the case; therefore we
can legitimately extract either one of them. Also known as _Simplification_.

![](/img/conjunc-elim.png)


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: 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: Heap_memory
last_modified: 2024-10-18 18:55:56
body:
# Heap memory

Along with [[Stack_memory|Stack memory]], programs make use of _heap memory_
during runtime.

Heap memory does not use a standardised data structure and can be accessed from
any point within the program.

Whereas stack memory with it's LIFO structure has memory management built-in
when programs allocate memory from the heap they must manually deallocate it
when it is no longer required. This process of "freeing memory" is known as
_garbage collection_. In a language like C, this is the explicit concern of the
programmer and is not abstracted away. Failure to properly manage garbage
collection is what causes [[Memory_leaks]].

Heap memory is used in combination with the stack since a given heap memory
allocation address is stored as a stack variable during runtime. It points to
the heap memory address whilst not being that memory itself.

Here is an example of managing heap memory allocation in C:

```c
void * data;
data = malloc(512)
```

The first line assigns a special _pointer_ variable (indicated by `void *`
rather than `int` or `str`) . This is a variable only holds a memory address.
The `malloc` method requests 512 bytes that it wants to assign to the `data`
variable. It will return the address of the first byte in the newly allocated
memory. `data` will then refer to the address on the stack that holds the
address allocation on the heap.

## Related notes


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: 3f1b9fe5_motivation_Berners_Lee
last_modified: 2024-10-28 15:41:28
body:
# 3f1b9fe5_motivation_Berners_Lee

TBL describes his motivation in creating the WWW as the desire to marry two
separate concepts/technologies: hypertext and the Internet, after both had come
of age.


title: Validity_and_entailment
last_modified: 2024-10-19 10:01:40
body:
# Validity and entailment

### Informal definition

In order to say whether an argument is 'good' or 'bad' we must have criteria of
evaluation. in logic there are different criteria of evaluation:

- **Deductive validity**

  An **argument is deductively valid if and only if it is not possible for the
  premises to be true and the conclusion false**. Linking to consistency: it is
  not possible to consistently assert all of the premises but deny the
  conclusion.

- **Inductive strength**

  We do not say that inductive arguments have 'validity' because despite
  inductive premises being true, the conclusion may be falsifiable. Therefore we
  say inductive 'strength' rather than 'validity'. An argument is inductively
  strong if and only if the conclusion is probably true given the premises.

#### Demonstration

The Socrates demonstration above is an example of deductive validity.

The following is an example of an argument that is inductively strong:

```
99% of deaf persons have no musical talent.
Beethoven was deaf.
___________________________________________
Beethoven had no musical talent.
```

The test for a strong inductive argument is not whether the conclusion is true,
rather it concerns the evidence the premises provide in support of the
conclusion.

> In propositional logic we are concerned solely with deductive validity or
> invalidity.

### Formal definition

> An argument is truth-functionally valid if and only if there is no
> truth-assignment on which all the premises are true and the conclusion is
> false.

Linking this to derivation, we say:

> In a system of derivation in propositional logic, an argument is valid if the
> conclusion of the argument is derivable within the system of derivation from
> the set consisting of the premises, and invalid otherwise.

### Demonstration

The inference from the set ${P, P \rightarrow Q}$ to $Q$ is valid

### Truth-table

| $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
| --- | --- | ----------------- | --- | --- | ---------- |
| T   | T   | T                 | T   | T   | Valid      |
| T   | F   | F                 | T   | F   |            |
| F   | T   | T                 | F   | T   |            |

## Entailment

### Informal definition

Entailment as a concept is almost identical to validity. We say that a
proposition is entailed by a set of propositions if it is not possible for every
member of this set to be true and the proposition to be false.

The difference with validity resides in the fact that the propositions are
distinguished in terms of whether they are premises or a conclusion. So,
technically, validity is a subclass of entailment. A case of entailment where we
distinguish propositions in terms of whether they are premises or conclusions. A
proposition may be entailed by a given set without that proposition being the
_conclusion_ of the set and where the set is a syllogism.

### Formal definition

> A finite set of sentences $\Gamma$ $\vdash$ $P$ if and only if there is no
> truth-assignment in which every member of $\Gamma$ is true and $P$ is false.

#### Informal demonstration

```
It is raining.
If it is raining then the pavement will be wet.
The pavement is wet.
```

#### Formal demonstration

$$
  \{ P, P\rightarrow Q   \} \vdash Q
$$

#### Truth-table

| $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
| --- | --- | ----------------- | --- | --- | ---------- |
| T   | T   | T                 | T   | T   | Valid      |
| T   | F   | F                 | T   | F   |            |
| F   | T   | T                 | F   | T   |            |


title: The_PATH
last_modified: 2024-10-18 18:55:56
body:
# The `$PATH`

We know that `$PATH` is an
[environment variable](Environmental_and_shell_variables.md).
This variable keeps track of directories **where executables are found**.

Whenever any command is run, the shell looks up the directories contained in the
`PATH` for the target executable file and runs it. We can see this is the case
by using the `which` command which traces the executable of bash commands. Take
the `echo` program:

```bash
which echo
# echo: shell built-in command
```

Or `npm` :

```bash
which npm
/home/thomas/.nvm/versions/node/v19.4.0/bin/npm
```

By default the path will always contain the following locations:

- `/usr/bin`
- `/usr/sbin`
- `/usr/local/bin`
- `/usr/local/sbin`
- `/bin`
- `/sbin`

All the inbuilt terminal programs reside at these locations and most of them are
at `/usr/bin`. This is why they run automatically without error. If you attempt
to run a program that doesn’t reside at these locations then you will get an
error along the lines of `program x is not found in PATH`.

## Structure of the PATH

```bash
/home/thomas/.nvm/versions/node/v19.4.0/bin:
/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:
/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
```

## Adding to the PATH

Only the default directories load to the PATH on every session. How then can we
add custom directories to the path without them being lost every time we start a
new session? Remember that the user config `.bashrc` loads on init for every
bash session. Therefore, if we set the custom path in this file, it will be
created every time we start a session. This is why when you add a new program it
often ask you to append a script to the bottom of your `.bashrc` .

For example, at the bottom of my `.zshrc` on my work computer I have:

```bash
export CHROME_BIN=/mnt/c/Program\\ Files\\ \\(x86\\)/Google/Chrome/Application/chrome.exe
```

This enables me to access the Chromium binaries from my terminal session (needed
for running Angular tests) but it doesn’t add it to the path, it creates an
environment variable on every session.

For demonstration, let’s add a user’s desktop directory to the PATH.

First we go to the `.bashrc` and add the `export` command. Remember that this is
the command for creating a new environment variable:

```bash
export PATH="$PATH=:~/Desktop"
```

We force a reload of the `.bashrc` with the command:

```bash
source ~/.bashrc
```

Then we can check this directory has been added to the path with an echo

```bash
echo $PATH
...:~/Desktop
```


title: 4da22434_from_ARPANET_to_Internet
last_modified: 2024-10-28 15:54:00
body:
# 4da22434_from_ARPANET_to_Internet

By the mid-1970s many additional computer networks had emerged which also used
#packet-switching.

It was the success of ARPANET as a "proof of concept" for packet-switching that
led to these additional networks being created in other countries and contexts.
Some used different modes of transmission than the #ARPANET's phone-wire based
system such as radio waves and satellites. However this created a problem: these
networks were siloed from each other and a bridge was needed to connect them.

Those working on the ARPANET steering committee (the Information Processing
Techniques Office (IPTO) within ARPA/DARPA) began to discuss what they called a
"concatenated network" or "CATENET" that would connect these different networks
together. Thus emerged the idea of a _network of networks_ or _inter-network_.

For this to work it would be necessary to construct "gateways": routing
computers that would hand-off messages from one network to another.

This required a new protocol because the Network Control Protocol was only
designed to work _within_ the ARPANET with its IMPs. Unlike the IMPs, the
gateways would not be responsible for reconstituting packets or ensuring
reliability, this would be shifted to the hosts. The protocol was the
[Transmission Control Protocol/Internet Protocol](Internet_Layer_of_Internet_Protocol.md).
TCP would be responsible for packet assembly and disassembly and IP for routing.

The "common language" of TCP/IP and the growth in networks in addition to the
ARPANET is what formed the Internet. Different commercial groups and research
enterprises inaugurated their own networks and, one-by-one, they adopted TCP and
became accessible to each other.

As the ARPANET was retired, its individual sites either became nodes within the
Internet or they split off into sub-networks such as MILNET (which was part of
the ARPANET retained for classified military communication). The IMPs were
retired in favour of TCP/IP routers.

_The ARPANET in 1973_

![](../img/Arpanet_map_1973.jpg)

_The ARPANET as part of an inter-network 1977_

![](../img/internetworking_1977.jpg)

_The ARPANET in 1977_

![](../img/Arpanet_logical_map,_march_1977.png)

_The Internet in 1984_

![](../img/internet_1984.jpg)


title: Zero_property_of_multiplication
last_modified: 2024-10-19 10:02:28
body:
# Zero property of multiplication

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

$$ a \cdot 0 = 0 $$


title: Custom_types_in_TypeScript
last_modified: 2024-10-18 18:55:56
body:
# Custom types

Objects and [classes](Classes.md) are where TypeScript becomes most useful and
powerful. In TypeScript, objects and classes are by definition custom types.

When typing objects, you do not write the types alongside the actual data as you
would with primitive types, classes and functions. Instead you write a custom
type which is a type-annotated object. This is then applied to the object or
class, where you create instances that **match the shape** of the custom
declaration.

So say we have this object:

```js
const age = {
  name: "Thomas",
  yearOfBirth: 1988,
  currentYear: 2021,
  ageNow: function () {
    return this.currentYear - this.yearOfBirth;
  },
};
```

We could write this as type with the following:

```ts
let Age: {
  name: string;
  yearOfBirth: number;
  currentYear: number;
  ageNow: () => number;
};
```

(We use `:` because we are declaring a type not intialising a value of the
type.)

We could now re-write the first `age` object as an object of type `Age` :

```tsx
let thomas: typeof Age;

thomas = {
  name: "Thomas",
  yearOfBirth: 1988,
  currentYear: 2021,
  ageNow: function () {
    return this.currentYear - this.yearOfBirth;
  },
};
```

In practice, defining the type and then asserting that a new variable is of this
type and then initialising it is rather long-winded. It is better practice to
simplify the process by creating a **type alias**.

```tsx
type Age = {
  name: string;
  yearOfBirth: number;
  currentYear: number;
  ageNow(): number; // we type the method on the basis of the value it returns
};
```

We could then create objects based on this:

```tsx
const thomas: Age = {
  name: "Thomas",
  yearOfBirth: 1988,
  currentYear: 2021,
  ageNow: function () {
    return this.currentYear - this.yearOfBirth;
  },
};
```

Note that we pass in `:Age` as our type declaration, using the custom type in
the same way as we would use `:string` or `number[]` . We can now use this
custom type as a type annotation anywhere we use type annotations; it can be
used exactly the same way as a primitive type in our code.

`Age` is an alias for the type that `thomas` conforms to.

The benefit is that TS will correct you if:

- attempt to assign a type to a value that does not match the custom type
  declaration (for instance: assigning a string value to a property you have
  typed as number)
- attempt to add a property that is not specified in the custom type declaration

Although you can subsequently _extend_ the custom type (detailed below).

## Duck typing

> Types are defined by the collection of their properties not their name.

Typescript's implementation of types is as a **structural type system**, which
contrasts with a nominal type system. This is often referred to colloquially as
'duck typing': _if it looks like a duck, walks like a duck, and sounds like a
duck, it probably is a duck_.

With custom (object types) this means that the following expression of an object
of type `Age` doesn't generate an error, TS is satisfied that the shapes of each
match.

```tsx
const martha = {
  name: "Martha",
  yearOfBirth: 1997,
  currentYear: 2021,
  gender: "female",
};

const addition: Age = martha;
```

But if we tried to add this extra property whilst defining `martha` as an
instance of the custom type `Age` , we would get an error:

```tsx
const martha: Age = {
  name: "Martha",
  yearOfBirth: 1997,
  currentYear: 2021,
  gender: "female",
};
```

```
Type '{ name: string; yearOfBirth: number; currentYear: number; ageNow: () => number; gender: string; }' is not assignable to type 'Age'. **Object literal may only specify known properties, and 'gender' does not exist in type 'Age'.**
```

It means that even though in the following, the variable `point` is never
declared to be of the type `Point` , it matches the shape of the custom type. As
the structural integrity is maintained, it can be passed to the function without
error.

```tsx
interface Point {
  x: number;
  y: number;
}

function logPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

// logs "12, 26"
const point = { x: 12, y: 26 };
logPoint(point);
```

Shape matching only requires a subset of the object's fields to match:

```tsx
const point3 = { x: 12, y: 26, z: 89 };
logPoint(point3); // logs "12, 26"

const rect = { x: 33, y: 3, width: 30, height: 80 };
logPoint(rect);
```

## Interfaces

For most purposes the keywords `type` and `interface` are interchangeable in
TypeScript.

(The main difference that I have encountered is that Angular specifies that
interfaces should be used over types, but this is because it is class-based and
object oriented).

For me, the main decider is that Angular favours `interface` over `type`. The TS
handbook recommends using the `type` keyword over `interface`.

An interface is concept that crosses over from strict OOP and it doesn't quite
apply to interfaces in TS because an interface is a declaration of a class's
functions alone, not its data (i.e properties).


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: AWS_SAM_and_Docker
last_modified: 2024-10-18 18:55:56
body:
# AWS SAM and Docker

_How would you use docker containers in AWS. How would this integrate with SAM.
What are the benefits over just deploying from local via SAM_

Amazon Web Services (AWS) provides several services for running Docker
containers, such as Amazon Elastic Container Service (ECS) and AWS Fargate. To
integrate Docker containers with AWS Serverless Application Model (SAM), you can
use the AWS Lambda container image support feature, which allows you to package
and deploy Lambda functions as container images.

Here's a brief overview of how to use Docker containers in AWS with SAM:

1. Create a Dockerfile for your Lambda function, using one of the AWS-provided
   base images for your preferred runtime (e.g., Python, Node.js, etc.).
2. Build the Docker image using the docker build command.
3. Push the Docker image to Amazon Elastic Container Registry (ECR) using the
   docker push command.
4. In your AWS SAM template (template.yaml), define a Lambda function with the
   ImageUri property pointing to the Docker image stored in ECR.
5. Deploy the serverless application using the sam deploy command.

## Benefits of using Docker containers with AWS SAM over deploying from local:

- Consistency:

  - Packaging your Lambda function as a container image ensures that the
    environment and dependencies are consistent across development, testing, and
    production stages. It eliminates the "it works on my machine" problem.

- Custom runtimes:

  - AWS Lambda provides a set of pre-defined runtimes, but with container image
    support, you can use custom runtimes, giving you more flexibility and
    control over the execution environment.

- Easier dependency management:

  - For complex applications with numerous dependencies or large package sizes,
    using container images simplifies dependency management and can help you
    stay within the Lambda package size limits.

- Reuse of existing Docker workflows:

  - If you already have Docker workflows in place for building, testing, and
    deploying containerized applications, you can easily extend these workflows
    for your Lambda functions, reducing the learning curve and operational
    overhead.

- Ease of local testing:
  - With AWS SAM CLI, you can test your Lambda functions locally as container
    images, closely mimicking the actual execution environment and reducing the
    chances of unexpected issues when deploying to AWS.

> While using Docker containers with AWS SAM has its benefits, it may not be
> suitable for every use case. If your Lambda functions have minimal
> dependencies and simple execution environments, deploying directly from local
> using SAM might be more straightforward and faster. However, for more complex
> applications, using Docker containers can provide better consistency,
> flexibility, and control over the execution environment.


title: Loops_in_bash
last_modified: 2024-10-18 18:55:56
body:
# Loops in Bash

## Traditional for loop

```bash
for (( i=0; i<=5;i++  )); do
  echo $i
done

# 1 2 3 4 5
```

## `for..in`: loop through an array

```bash
for element in "${arr[@]}"
do
    echo "$element"
done
```

## While loop

> `while` loops execute while a condition is true (0)

We can use a `while` loop as a condition in two senses:

- execute while a given condition obtains
- expand and execute a given command as long as the final command in the `while'
  for the command has an exit status of zero (i.e. truthy)

Here is an exampe of using `while` in the former case:

```sh
declare -i n=0
while (( n<10 ))
do
  echo "n:$n"
  (( n++ ))
done
```

Here is an example of using `while` in the latter case:

```sh
while read line;
do
    # something
done < "$file_to_read"
```

## Until loop

> `until` loops execute until a condition is false (1)

```sh
declare -i m=0
until (( m==10 )): do
  echo "m:$m"
  (( m++ ))
done
```

This gives us the same output as `n` with the while loop but here it runs so
long as `m==10` is false. As soon as `m` is equal to 100, the condition becomes
true and hence the loop stops.


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: 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: 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: 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: Threads
last_modified: 2024-10-24 17:25:42
body:
# Threads

A ![process](Processes.md) is a running instance of a given program. A program
runs sequentially handling one task at a time, however we may need to run
certain tasks in parallel.

Think of a program that is downloading a resource from the internet and wants to
update the UI at the same time to show the download process.

If the program is strictly sequential, once the program starts the download, the
UI is neglected since the CPU time dedicated to the process must be focused
elsewhere.

We need the UI update and the download to execute in parallel. This is achieved
via operating system **threads of execution**.

> A thread is a schedulable unit of execution within a process. It runs within a
> process, shares its memory address and can execute any program code loaded
> within it.

Each thread has an identifier called a _thread ID_ (TID).

Both procesess in [user space](User_Space.md) and the [kernel](The_kernel.md)
utilise threads.

## Hardware considerations

Each [processor core](CPU_architecture.md) can only run one thread at a time so
the number of cores that a device's CPU has deterimines how many threads can run
at once. In practice, then, the CPU shuffles between multiple threads in
[clock segments](Clock_signals.md). This is known as scheduling and is managed
by the process that the thread belongs to.

## Related notes

![Processes](Processes.md)


title: Module_wrapping_at_runtime
last_modified: 2024-10-18 19:17:23
body:
# Module wrapping at runtime in NodeJS

## The Module Wrapper Function

When Node runs each of our module files are wrapped within an
immediately-invoked function expression that has the following parameters:

```js
(function (exports, require, module, __filename, __dirname))

```

This is called the **module wrapper function**

Note that one of these parameters is the
[module object](Modules_in_NodeJS.md#structure-of-a-module).

Within any module we can access these parameters: you can think of them as
metadata about the module itself. `__filename` and `__dirname` are particularly
useful when writing to files and modifying directories.


title: Binary_colour_encoding
last_modified: 2024-10-18 18:55:56
body:
# Binary encoding of colours

The approach to encoding binary representations of colour is very similar to the
approach we explored when looking at the encoding of
[alphanumeric values](Text_encoding.md).

We begin by determining the total number of colours and colour shades we want to
represent. With this value established we then decide on the bit-length required
that will accomodate this number of variations. Finally, we assign a binary
number to each representation.

### Greyscale

We can start with a limited palette: greyscale. Here there is black and white
and number of interim shades of grey. The convention is to use an 8-bit number
which, given $2^8 = 256$ provides 256 shade variations.

In decimal, 0 is equal to black (zero light intensity) and 255 is equal to white
(full light intensity). Some examples of this (including binary and hex
representations are below):

![](/img/greyscale-encoding.svg)

### Colour encoding

A single 8-bit number is sufficient for 256 greyscale combinations but with
colour, the convention is to use three 8-bit numbers where each byte corresponds
to a value for red, green and blue (RGB). Thus the overall bit-length is 24
($2^3 + 2^3 + 2^3$). Each value corresponds to a light intensity for the given
colour. Combined they are capable of representing all colours.

Some examples below

#### Red

Red is represented in RGB with all 8 red bits to set to 1 and the remaining 16
bits for the other two colours set to 0.

![](/img/red-encoding.svg)

#### Yellow

Yellow is represented in RGB with both red and blue set to 1 and the remaining 8
green bits set to ):

![](/img/yellow-encoding.svg)

## Binary encoding of images


title: Inversion_of_operators
last_modified: 2024-10-18 19:15:36
body:
# Inversion of operators

## Addition, subtraction

Addition is the inverse of subtraction: $$(x - a) + a = x$$ $$ (6 - 2) + 2 = 6

$$

Subtraction is the inverse of addition: $$(x + a) - a = x$$ $$ (3 + 2) - 2 = 3$$

Division is the inverse of multiplication $$ \frac{a \cdot x}{a} = x$$
$$ \frac{6
\cdot 3}{6} = 3
$$

Multiplication is the inverse of division $$ a \cdot \frac{x}{a} = x$$

$$
2 \cdot
\frac{8}{2} = 8
$$


title: Cells_and_batteries
last_modified: 2024-10-18 18:55:56
body:
# Cells and batteries

Cells are a
[voltage source](Voltage.md) that
generate a difference of potential via a positive and negative electrode
separated by an electrolytic solution. The electrolytes pull free electrons from
one of the materials which creates a positive charge. The other material gains
the free electrons creating a negative charge.

> A battery is a combination of two or more cells.

> Cells which cannot be recharged are called **primary cells**. Cells which can
> be recharged are called **secondary cells**.

## Connecting batteries

Cells and batteries can be connected to each other in electrical ciruits to
increase the overall voltage and current that is produced. There are three main
connection types:

- series
- parallel
- series-parallel

> The key thing to remember: **cells configured in series increases the overall
> voltage available** and **cells configured in parallel increases the overall
> current available**

The table below summarises the relative differences:

![](/img/cell-comparison.svg)

### Series connections

With series connections we distinguish **series aiding** and **series opposing**
configurations.

In the case of **series aiding**, cells are connected one in front of another
with the positive terminal connecting to the negative terminal of the other in a
line.

In this configuration the same current flows through all the cells; it is not
cumulative. We represent this as follow> However the voltage is cumulative: it
is the _sum_ of the individual cell voltages, represented below as
[electrical field](Voltage.md#distinguishing-voltage-from-electric-field):

$$
E_{T} = E_{1} + E_{2} + E_{3} \\
$$

Thus series connections increase voltage but keep current constant.

_Series battery connection:_

![](/img/series-battery-diagram.svg)

_Can be represented in a circuit diagram in one of the following two ways: as a
series of cells or as a single battery:_

![](/img/series-battcircuit.svg)

In the case of **series opposing**, negative terminals are connected to each
other and positive terminals are connected to each other in a series. This
doesn't have many applications.

### Parallel connections

In parallel connections all positive terminals are connected to each other and
all negative terminals are connected to each other.

This time the voltage is the same as each individual cell but the current is the
sum of the individual cell currents. So the voltage is constant but the current
is cumulative:

$$
E_{T} = E_{1} = E_{2} = E_{3} \\
$$

$$
I_{T} = I_{1} + I_{2} + I_{3}
$$

_Parallel battery connection:_

![](/img/parallel-battery-diagram.svg)

_Parallel battery circuit diagram:_

![](/img/circ-batt-final.svg)

### Series-parrallel

If we want both a higher voltage and a higher current we can use series-parallel
configurations. Connecting cells in series increases the voltage and connecting
cells in parellel increases the current so doint both boosts the amount of both
quantities.


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: Apollo_Client
last_modified: 2024-10-18 18:55:56
body:
# Apollo Client

Apollo Client is the client-side counterpart to
[Apollo Server](Apollo_Server.md). We use it for
managing queries and mutations from the frontend to our Apollo GraphQL server.
It is specifically designed to work with React.

> We will be working with the
> [schema](Apollo_Server.md#example-schema) we defined
> when working on the server

## Initializing the client

We initialise the client and set-up in memory caching to reduce network
requests:

```js
const client = new ApolloClient({
  uri: "http://localhost:4000",
  cache: new InMemoryCache(),
});
```

> The `uri` property must match the location of our Apollo server.

## Utilising the provider

Apollo provides a top level application context that we can wrap our React app
in. This will provide access to the client object from anywhere within the app,
eg:

```jsx
ReactDOM.render(
  <ApolloProvider client={client}>
    <GlobalStyles />
    <Pages />
  </ApolloProvider>,
  document.getElementById("root")
);
```

## Running a query

### Queries as entry points

From the client point of view, the queries in the schema are _entry points_.
Although the queries exist in the schema, this alone is not sufficient for them
to be entry points. Remember a schema is just a specification or contract
between the frontend and the backend, it is not itself executable code.

Therefore, for each query in the schema we must write a frontend implementation.
We do this with **query constants**. The frontend implementation has a backend
analogue: the
[resolver](Apollo_Server.md#implementing-resolvers)
that is invoked when the frontend issues a query. The schema standardises this
relationship so that every query on the client must have a corresponding
resolver on the backend.

### Query constants

To run a query against our server we must define a query contant first. We use a
`gql` literal again:

```js
import { gql } from "@apollo/client";
const TRACKS = gql`
  query GetTracks {
    tracksForHome {
      id
      title
      thumbnail
      length
      modulesCount
      author {
        name
        photo
      }
    }
  }
`;
```

The convention is to name the query constant in `ALL_CAPS`.

> Note that the name of the query on the client doesn't have to match the query
> type defined in the schema (there is no `GetTracks` in the schema), this is
> just a client-side designator. However it should reference the schema on the
> second line (`tracksForHome`).

### `useQuery` hook

The `useQuery` hook provides a straightforward wrapper for sending queries and
receiving data back from the server.

When a component renders, `useQuery` returns an object from the Apollo Client
that contains loading, error, and data properties.

```jsx
const { loading, error, data } = useQuery(TRACKS);

const Tracks = () => {
  const { loading, error, data } = useQuery(TRACKS);

  if (loading) return "Loading...";

  if (error) return `Error! ${error.message}`;

  return <Layout grid>{JSON.stringify(data)}</Layout>;
};
```

- We destructure the `loading, error, data` variables that are returned from the
  hook
- We pass in our query constant as an argument.
- In the example we just render the serialized data but we could of course pass
  the data as a prop and map through it in an embedded child component.


title: User_Space
last_modified: 2024-10-18 18:55:56
body:
# User space

User space is the portion of the main memory that the kernel allocates for user
processes.

There is a hierarchy within the user space with several different groups of user
processes:

<dl>

<dt>Basic services</dt>
<dd>Run at the bottom level and therefore are closest to ther kernel. Comprises small components that perform single, uncomplicated tasks. Examples include network configuration, the communication bus, and diagnostic logging</dd> 
<dt>Utiility services</dt>
<dd>The middle level: larger components such as mail, print, and database services</dd>
<dt>Services controllable by the user</dt>
<dd>The top level: complicated tasks that the user controls directly such as using a web-browser, editing a text file</dd>
</dl>

## What is a user?

> A user is an entity that can run processes and own files.

At the level of users, a user is associated with a user name however the kernel
does not manage usernames, it identifies users via numeric identifiers called
**user IDs**.

Users exist in order to support permissions and access boundaries. A user may
terminate or modify the behaviour of its own processes (within limits) but
cannot interfere with another user's proceses. In addition, users may own files
and choose whether to share them with other users.

### Root user (superuser)

A Linux system normally has a number of users in addition to the ones that
correspond to the real human users. The most important is **root**. The root
user _can_ terminate and alter another user's processes and access any file on
the local system.

A person who can operate as root is an administrator on a typical user system.


title: Concise_subfield_mapping_JS
last_modified: 2024-11-04 15:20:00
body:
# Concise mapping of object subfields in JS

## Scenario

You have an array of objects and you want to return the objects with only a
subset of the fields.

## Implementation

Standard approach with a map:

```js
const arrayOfObjs = [
  { id: 12, name: "Thomas" },
  { id: 3, name: "Gerald" },
];

// We just want the `name` property

const subset = arrayOfObjs.map((obj) => {
  name: obj.name;
});
```

More concise approach with destructuring:

```js
const subset = arrayOfObjs.map(({ name }) => ({ name }));
```

## Related notes


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: Hardware_Description_Language
last_modified: 2024-10-18 18:55:56
body:
# Hardware Description Language

An HDL is a declarative programming language used to describe the behaviour or
structure of
[digital circuits](Integrated_circuits.md).
They are used to simulate the circuit and check its response.

The hardware designer specifies a chip's logic by writing an HDL program which
is then rigorously tested. At this stage, a
[hardware simulator](Hardware_simulation.md) takes the
HDL program as input and creates a software representation of the chip logic.
The designer can instruct the simulator to test the virtual chip on various sets
of inputs. This is done to check the chip's functionality but also to benchmark
a variety of other parameters such as speed of computation and energy
consumption.

There are many HDLs but the most popular are VHDL ("very high speed
integrated-circuit description language") and Verilog.

## Usage in _NAND to Tetris_

We won't use an actual HDL language, instead we will use a simplified toy
language called HDL that is simple enough that when it is used with a simulator,
we can learn the main facets of chip design. Its syntax is very similar to VHDL.

## Demonstration of HDL program

### Boolean function to enact

We will create an HDL program for an XOR gate that is implemented through the
following arrangement of NOT, AND, and OR gates:

![](/img/xor-hdl.png)

### HDL file (`Xor.hdl`):

Here is our HDL file:

```
/* Xor gate
   If a!=b out=1 else out=0
*/
CHIP Xor {
  IN a, b;
  OUT out;
  PARTS:
  Not (in=a, out=nota);
  Not (in=b, out=notb);
  And (a=a, b=notb, out=w1);
  And (a=nota, b=b, out=w2);
  Or  (a=w1, b=w2, out=out)
}
```

#### Interface (`CHIP, IN, OUT`)

At the top level of the HDL program, the `CHIP` name and `IN`/`OUT` declaration
is the _interface_ of the chip. Here we specify our naming convention for the
`IN` and `OUT` values which we will refer to in the implementation declaration
in `PARTS`.

#### Implementation (`PARTS`)

Everything under the `PARTS` section is the chip _implementation_. We can draw
on composite gates in the `PARTS` declaration (e.g. `Not`, `And`, `Or`). The
convention is to work from left to right when transcribing from a digital
circuit diagram

#### Pins

In an HDL program we distinguish internal pins along with the standard
[input and output pins](Integrated_circuits.md).
At the level of the interface, we are concerned only with input and output pins
(in the example program these are `a`, `b` and `out`). It is at the level of the
implementation that internal pins are encountered. In the example these are the
connections between, e.g. the AND and NOT gates such as
`And (a=a, b-notb, out=w1)`. This means the AND gate is receiving through its
`a` pin the input `a` value and through its `b` pin the value of `b` inverted by
a NOT. `out` is the value that is computed based on the input pins of `a` and
`b`.

### Test file (`Xor.tst`)

Along with the HDL file we also create a test file. This runs the chip against
the inputs we supply, these will typically be equivalent to the (left-hand)
truth-values column in a truth table which is the same as the parameters passed
to a [Boolean function](Boolean_functions.md), for
example:

```vhdl
load Xor.hdl
output-list a, b, out;
set a 0, set b 0, eval, output;
set a 0, set b 1, eval, output;
set a 1, set b 0, eval, output;
set a 1, set b =, eval, output;
```

### Output file (`Xor.out`)

When the test file is run against the HDL file it will generate an output file.
This is effectively the result of the unit test. And will take the form of a
truth table:

```
a | b | out
-----------
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
```


title: DynamoDB_CLI_commands
last_modified: 2024-10-18 18:55:56
body:
# DynamoDB CLI commands

## Connecting to a local (Docker)/prod (AWS) DynamoDB instance

In order to distinguish between local and production accounts you should keep
seperate profiles for each (via `.aws/config` and `.aws/credentials`).

When connecting to a local DB use the local profile and the local URL. Without
the `--profile` flag, AWS will default to the `default` profile which will
typically be your credentials for accessing AWS on the remote.

It also sometimes required to add the endpoint-url when working locally:

```
--endpoint-url http://localhost:800

> When using the commans below locally, assume `--endpoint-url` and `--profile`
> have been appended

```

For example:

```sh
aws dynamodb list-tables \
--profile timetracking_dev \
--endpoint-url http://localhost:800
```

## Delete a table

```sh
aws dynamodb delete-table \
--table-name TableName
```

## Create table from JSON schema

```sh
aws dynamodb create-table \
--cli-input-json file://create-timeentries-table.json \

```

## Describe the table

View the table schema:

```sh

aws dynamodb describe-table \
--table-name TimeEntries
```

## Scan the table

```sh
aws dynamodb scan \
--table-name TimeEntries \
--output table
```

## Related notes


title: Boot_process
last_modified: 2024-11-04 14:22:36
body:
# Boot process

The primary or boot
[partition](Disks.md#primary-extended-and-logical-partitions) of a harddisk
contains a bootloader. It is the job of the bootloader to locate the
[kernel](The_kernel.md) on the harddrive and inject it into memory so that they
operating system can start. This is the boot process.

## Boot loaders

The boot loader loads the kernel into memory from the disk and then starts the
kernel with a set of kernel parameters.

Like the kernel itself, the boot loader requires a driver in order to access the
disk but it can't use the same one as the kernel since at this point, the kernel
is not yet loaded into memory. So it has its own special driver: this is either
the BIOS or the UEFI firmware.

A boot loader's core functionality includes the ability to do the following:

- select from multiple kernels
- switch between sets of kernel parameters
- provide support for booting other operating systems

### BIOS and UEFI

BIOS and UEFI are both firmware that is installed directly on the motherboard of
the computer. They are firmware because they are software that is permanent and
programmed into read-only memory.

In the context of disks, their most crucial role is locating the operating
system on the harddisk and loading it into memory so that the bootstrapping
process can begin. However they are also responsible for the computer clock and
the management of peripherals.

As we can see from the `fdisk` readout, the boot partition uses EFI, the storage
partition associated with UEFI.

```bash
Device            Start        End   Sectors   Size Type
/dev/nvme0n1p1     2048    1001471    999424   488M EFI System
/dev/nvme0n1p2  1001472   59594751  58593280  27.9G Linux filesystem
/dev/nvme0n1p3 59594752 1000214527 940619776 448.5G Linux filesystem
```

Whilst UEFI is installed on the hardware, most of its configuration is stored in
the EFI partition on the disk, whereas with BIOS, everything is on the chip.
This makes booting faster with UEFI.

Even though most modern computers use UEFI, it may still be referred to as BIOS
for user-continuity (for instance on WIndows). With Linux you have to explicitly
create your boot process so the two are clearly distinguishable.

### GRUB

The de facto standard boot loader for Linux is GRUB: Grand Unified Boot Loader.

![](/img/grub.jpg)

You see the GRUB default menu when you first start a Linux machine. It will
offer you various options for loading your installed OS or other OSs. GRUB is a
[filesystem](./Filesystems.md) like the main disk. If you press `e` in this
screen you can view and edit specific boot parameters. Pressing `c` gives you
access to the GRUB command line interface. This allows you to interact with GRUB
in the same way as you would with any other filesystem, allowing for advanced
configuration.

## The boot sequence

1. The machine's BIOS or boot firmware (in the case of UEFI) loads and runs a
   boot loader. It finds the bootloader by looking for the part of the disk that
   contains either the MBR or GPT sector.
2. The boot loader finds the kernel image on disk, loads it into memory and
   starts it.
3. The kernel initializes the devices and its drivers.
4. The kernel mounts the root filesystem.
5. The kernel starts a program called **init**. It has a
   [process id](Processes.md#processes-ps) of 1. This is the point at which
   [user space](User_Space.md) starts.
6. Init sets the rest of the system processes in motion.
7. At the end of the boot process, init starts a process allowing you to log in.

## Boot diagnostics

Linux keeps a log of the boot process as part of the [journal](./journald.md)
log of everything that happens on disk. We can use the command `journalct -k` to
view the diagnostics generated during the boot. Here is a selection:

```
Jul 07 07:12:58 archbish kernel: Linux version 5.18.5-arch1-1 (linux@archlinux) (gcc (GCC) 12.1.0, GNU ld (GNU Binutils) 2.38) #1 SMP PREEMPT_DYNAMIC Thu, 16 Jun 2022 20:40:45 +0000
Jul 07 07:12:58 archbish kernel: Command line: BOOT_IMAGE=/boot/vmlinuz-linux root=UUID=2ee6b834-0857-49dc-b8ba-a24d46d228ae rw loglevel=3 quiet
Jul 07 07:12:58 archbish kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jul 07 07:12:58 archbish kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
Jul 07 07:12:58 archbish kernel: x86/fpu: Supporting XSAVE feature 0x020: 'AVX-512 opmask'
Jul 07 07:12:58 archbish kernel: x86/fpu: Supporting XSAVE feature 0x040: 'AVX-512 Hi256'
Jul 07 07:12:58 archbish kernel: x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
Jul 07 07:12:58 archbish kernel: x86/fpu: xstate_offset[5]:  832, xstate_sizes[5]:   64
Jul 07 07:12:58 archbish kernel: x86/fpu: xstate_offset[6]:  896, xstate_sizes[6]:  512
Jul 07 07:12:58 archbish kernel: x86/fpu: xstate_offset[7]: 1408, xstate_sizes[7]: 1024
Jul 07 07:12:58 archbish kernel: x86/fpu: xstate_offset[9]: 2432, xstate_sizes[9]:    8
Jul 07 07:12:58 archbish kernel: x86/fpu: Enabled xstate features 0x2e7, context size is 2440 bytes, using 'compacted' format.
Jul 07 07:12:58 archbish kernel: signal: max sigframe size: 3632
Jul 07 07:12:58 archbish kernel: BIOS-provided physical RAM map:
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009efff] usable
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x000000000009f000-0x00000000000fffff] reserved
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x0000000000100000-0x000000008ef6efff] usable
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x000000008ef6f000-0x000000008f03efff] type 20
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x000000008f03f000-0x0000000093f2efff] reserved
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x0000000093f2f000-0x0000000094b2efff] ACPI NVS
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x0000000094b2f000-0x0000000094bfefff] ACPI data
Jul 07 07:12:58 archbish kernel: BIOS-e820: [mem 0x0000000094bff000-0x0000000094bfffff] usable
Jul 07 07:12:58 archbish kernel: NX (Execute Disable) protection: active
Jul 07 07:12:58 archbish kernel: efi: EFI v2.70 by Lenovo
Jul 07 07:12:58 archbish kernel: efi: ACPI=0x94bfe000 ACPI 2.0=0x94bfe014 SMBIOS=0x90cbd000 SMBIOS 3.0=0x90cb0000 TPMFinalLog=0x9498f000 MEMATTR=0x8aa30018 ESRT=0x8ab9c000
Jul 07 07:12:58 archbish kernel: SMBIOS 3.2.0 present.
Jul 07 07:12:58 archbish kernel: DMI: LENOVO 20W4000NUK/20W4000NUK, BIOS N34ET40W (1.40 ) 06/25/2021
Jul 07 07:12:58 archbish kernel: tsc: Detected 2400.000 MHz processor
Jul 07 07:12:58 archbish kernel: tsc: Detected 2419.200 MHz TSC
Jul 07 07:12:58 archbish kernel: e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
Jul 07 07:12:58 archbish kernel: e820: remove [mem 0x000a0000-0x000fffff] usable
Jul 07 07:12:58 archbish kernel: last_pfn = 0x45f800 max_arch_pfn = 0x400000000
Jul 07 07:12:58 archbish kernel: x86/PAT: Configuration [0-7]: WB  WC  UC- UC  WB  WP  UC- WT
Jul 07 07:12:58 archbish kernel: last_pfn = 0x94c00 max_arch_pfn = 0x400000000
Jul 07 07:12:58 archbish kernel: esrt: Reserving ESRT space from 0x000000008ab9c000 to 0x000000008ab9c150.
Jul 07 07:12:58 archbish kernel: e820: update [mem 0x8ab9c000-0x8ab9cfff] usable ==> reserved
```

We can see that the first thing that is registered is the OS image that contains
the kernel. From this point on, the kernel is active and doing its work.

## Initial kernel actions

The diagnostics above are a running commentary provided by the kernel itself
about its actions. The details will be specific to the machine in question but
the general sequence is as follows for all operating systems:

1. CPU inspection
2. Memory inspection
3. Device bus discovery
4. Device discovery
5. Auxiliary kernel subsystem setup (networks etc)
6. Mounting of the root filesystem
7. Starting of user space


title: Network_requests_in_Python
last_modified: 2024-10-18 18:55:56
body:
# Making network requests in Python

We can use the `requests` package to make API requests to
[RESTful](RESTful_APIs.md) resources and handle the data as JSON.

```sh
pip install requests
```

Here is a basic architecture for making a `GET` request in Python.

```python
import requests

def get_data(url):
    response = requests.get(url)
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(
            f"Failed to fetch data from API. Status code: {response.status_code}")

def main():
    url = "https://dummyjson.com/products/1"

    try:
        data = get_data(url)
        print(data)

    except Exception as e:
        prin(e)

if __name__ == "__main__":
    main()
```

## Parsing returned data

Running `main` returns:

```python
{
   "id":1,
   "title":"iPhone 9",
   "description":"An apple mobile which is nothing like apple",
   "price":549,
   "discountPercentage":12.96,
   "rating":4.69,
   "stock":94,
   "brand":"Apple",
   "category":"smartphones",
   "thumbnail":"https://i.dummyjson.com/data/products/1/thumbnail.jpg",
   "images":[
      "https://i.dummyjson.com/data/products/1/1.jpg",
      "https://i.dummyjson.com/data/products/1/2.jpg",
      "https://i.dummyjson.com/data/products/1/3.jpg",
      "https://i.dummyjson.com/data/products/1/4.jpg",
      "https://i.dummyjson.com/data/products/1/thumbnail.jpg"
   ]
}
```

This is JSON but in Python is a [dictionary](Dictionaries_in_Python.md)

We can use standard dictionary methods to handle the data. For example, we'll
add to the existing `try` block:

```python
example_key = "brand"  # Replace with the key you want to access from the JSON data
    if example_key in data:
        print(f"Value of '{example_key}':", data[example_key])
    else:
        print(f"'{example_key}' not found in the JSON data")
```

Which, if successful, outputs:

```
Value of 'brand': Apple
```


title: Connecting_a_frontend_to_a_Docker_backend
last_modified: 2024-10-18 18:55:56
body:
# Connecting a frontend to a Docker backend

Building on from
[NodeJS backend with MySQL database](Node_and_MySQL_db.md)
we can add a frontend by adapting the existing
[Docker Compose](Docker_Compose.md) files (one for each
environment) to accept an additional dependency.

We won't create a container for the frontend as this is not necessary.

We would add the following to the `services` section of the compose file:

```yml
services:
  ...
  frontend:
    build: ./frontend
    container_name: frontend_app
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://localhost:3001
    depends_on:
      - app
```

The `REACT_APP_API_URL` environment variable tells the frontend application
where to find the backend API. This will then be accessbile via `process.env`
and can be used directly in the frontend, e.g:

```js
fetch(`${process.env.REACT_APP_API_URL}/api/data`)
  .then((response) => response.json())
  .then((data) => {
    // Process the data from the backend API
  });
```


title: Chipset_and_controllers
last_modified: 2024-10-18 18:55:56
body:
# Chipset and controllers

A **controller** is simply a circuit that controls a process. The **chipset** is
a combination of controllers placed on the same piece of silicon.

The chipset manages the data flow between the different components that comprise
the [motherboard](Motherboard.md): processor,
[memory](Memory.md),
[harddisk](What_are_disks.md) and peripherals.

Buses run in and out of the chipset into these key motherboard components. The
main chipset is a kind of junction that sits between the memory and CPU through
which the [system bus](Bus.md) passes.

The chipset is sometimes called the "glue" or "traffic controller" of the
motherboard or _an intelligent intersection of buses_.


title: Find_Bash_command
last_modified: 2024-10-18 18:55:56
body:
# `find`

`find` can be used both to locate files and run operations on the files it
finds.

## Main syntax

### No options

Without options specified, `find` alone will return a recursive index of all the
files in the directory from which it is run.

### Sub-directory

If we pass a directory to `find` it will repeat the above process but
specifically for that directory.

```bash
$ find i3
i3
i3/config
```

### Filters

We can specify flags as filters (known as 'tests' within the program).

#### Type

Filter by type: file or directory

```
$ find -type d # return dirs only
$ find -type f # return files only
```

Within a specified directory:

```bash
$ find i3 -type f
```

#### Filename

This is the most frequent use case: filter files by name with globbing.

```bash
$ find -name "config"
./.git/config
./i3/config
```

```bash
$ find -name "*.js"
```

The same, but case insensitive: `iname`

```bash
$ find -iname "*.JS"
```

#### Path

As above but this time includes directory names in the match. `ipath` is the
case-insensitive version.

```bash
$ find -path "utils*"
utils.js
utils/do-something.js
```

### Operators

We can combine `find` commands by using logical operators: `-and`, `-or`,
`-not`. For example:

```bash
$ find -not -name "*.js" -type f
./app/index.html
./app/style.css
./dist/index.html
./dist/style.c
```

Applied to a directory:

```bash
find . -type -f -not -path "./.git/"
```

## Run programs against results

Using the `exec` keyword we can run a program against the files that are
returned from `find`.

In this syntax we use `{}` as a placeholder for the path of the file that is
matched. We use `;` (escaped) to indicate the end of the operation.

### Examples

This script deletes the files that match the filter criteria:

```bash
$ find -name "*.js" -exec rm {} \;
```

This script finds all the files with the substring 'config' in their name and
writes their file size to a file.

```bash
find -name '*config*' -exec wc -c {} \; > config-sizes
```


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: Reiteration
last_modified: 2024-10-18 18:55:56
body:
# Reiteration

**Reiteration (R)** allows us to restate any proposition already in the proof
within the main proof or a more deeply nested sub-proof. Reiteration allows us
to reuse any assumptions, or propositions derived from assumptions, without
having to introduce a new dependency with another assumption.

![](/img/reiteration.png)


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: 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: Memoization_in_React
last_modified: 2024-10-18 18:55:56
body:
# Memoization with useCallback and useMemo

## Rationale

In the lifecycle of a component, React re-renders the component when an update
is made. When React checks for any changes in a component, it may detect an
unintended or unexpected change due to how JavaScript handles equality and
shallow comparisons. This change in the React application will cause it to
re-render unnecessarily.

Additionally, if that re-rendering is an expensive operation, like a long for
loop, it can hurt performance. Expensive operations can be costly in either
time, memory, or processing. In addition to potential technical issues, this may
lead to poor user experience.

If one part re-renders, it re-renders the entire component tree. `useCallback`
and `useMemo` can be used reduce this performance impact.

## useCallback

The `useCallback` hook is used to wrap functions. It tells React to not
re-create a wrapped function when a component re-renders, unless any of the
useCallback's dependencies change.

`useCallback` returns a memoized version of the callback function it is passed.
This means that the function object returned from useCallback will be the same
between re-renders.

Remember that in JavaScript, functions are objects and components are functions.
As a result, every time a component containing a function re-renders, it create
a new instance of the function in memory.

> Given the same dependency value, the `useCallback` hook returns the same
> function instance between renderings (aka memoization).

This said, for small functions that are not intensive, it doesn't really matter
if they are not memoized.

### Syntax

A standard case of this would be a function that runs on a button click, for
instance when sending data from a form to a server. In the example below there
is quite a lot going on, and most of it is independent of the actual UI-cycle of
the component.

```jsx
const handleSubmit = useCallback(
  async (formValues) => {
    setPendSaveConfig(true);
    const payload = new GenerateConfig({
      workflowId: project_id,
      blockId: blockId,
      config: formValues,
    });
    axios
      .post(`${process.env.REACT_APP_ENDPOINT}/save-block-config`, payload)
      .then((res) => console.log(res))
      .finally(() => setPendSaveConfig(false))
      .catch((err) => console.error(err));
  },
  [blockId, project_id]
);
```

Note that the syntax is similar to [React_useEffect](React_useEffect.md): there is a
dependency array. The effect is the same: the function contained within
`useCallback` will only re-rendered if one of these dependencies changes.
However (see next section) the function will run in its memoized form on every
click.

### Reference versus result

`useCallback` only memoizes the function _object_ (the reference) not the value
that is _returned_ by the function (the result).

In the example below, the `calculatePi()` function reference will not change
between renders but each time the click event fires, the value returned by
`calculatePi()` will change. In other words, it will be assigned fresh memory.

```jsx
function ParentComponent() {
  const onHandleClick = useCallback(() => {
    const special = calculatePi();
  });

  return <SubComponent handleClick={onHandleClick} />;
}
```

### Use cases

You should not apply `useCallback` in a blanket fashion, this can reduce
performance rather than improve it. The best scenarios are:

1. A functional component wrapped inside React.memo() accepts a function object
   prop

2. When the function object is a dependency to other hooks, e.g.
   `useEffect(..., [callback])`

3. When the function has some internal state, e.g. when the function is
   debounced or throttled.

## useMemo

We can think of `useMemo` as a complement to `useCallback`. The main difference
is that whilst `useCallback` memoizes the function reference, `useMemo` memoizes
the function result; the value that is returned.

> In memoization, the result is “remembered” when the same parameters are
> passed-in subsequently. If we have a function compute 1 + 1, it will return 2.
> But if it uses memoization, the next time we run 1’s through the function, it
> won’t add them up; it will just remember the answer is 2 without executing the
> adding function.

Like `useCallback`, `useMemo` takes a function and an array of dependencies for
the same reason: if one of the dependencies changes then the function will
recalculate (and re-memoize) the result but they don't the same memoized value
will be returned.

As with `useCallback`, `useMemo` is best applied to complex functions that are
computationally expensive, it shouldn't be used indiscriminately.

It should not be used with asynchronous functions, in these instances,
`useEffect` would be a better choice.

### Syntax

```jsx
const List = React.useMemo(
  () =>
    listOfItems.map((item) => ({
      ...item,
      itemProp1: expensiveFunction(props.first),
      itemProp2: anotherPriceyFunction(props.second),
    })),
  [listOfItems]
);
```


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: Delay_line_memory
last_modified: 2024-10-18 18:55:56
body:
# Delay line memory

- First described in the _First Draft_ by #vonNeumann based on work by Eckert
  and Mauchley.

- Information is stored as acoustic waves travelling through a medium, typically
  mercury. As sound travels more slowly than electric charge (light), if
  electric signals are converted to sound, the delay time involved can be used
  as a type of store.

- It worked as follows:
  - Imagine we have an 8-bit number. The number is input as a sequence of pulses
    where a pulse is 1 and the absence of a pulse is 0.
  - The pulses are converted into sound waves (using a transducer, as with a
    speaker) and sent through a mercury-filled tube.
  - The length of the tube is calculated so that it takes exactly the time of
    one machine cycle for a pulse to travel from one end to the other
  - At the other end of the tube, another transducer converts the sound waves
    back to electrical pulses
  - This operates in a loop: the pulses go back into the input end of the tube
    and the cycle runs again.

To read the data, the computer would "listen" to the pulses coming out of the
receiving end. To write new data, the computer would inject new pulses at the
precise moment when it wants to change a '0' to a '1' or vice versa.

For an 8-bit number there would be 8 pulses for each bit and it would be
necessary to keep track of 8 specific positions in the delay line where each bit
would be stored.

The limitations were timing - difficult to keep track of each precise bit and
when it would arrive at the output. Also it was sequential rather than random
access. Not every bit could be accessed at once, you had to wait for its time
slot to come around to access it.


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: 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: 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: Key_characteristics_of_GraphQL
last_modified: 2024-10-18 18:55:56
body:
# Key characteristics of GraphQL

> In a nutshell, GraphQL is all about optimizing data communication between a
> client and a server. This includes the client asking for needed data and
> communicating that need to the server, and the server preparing a fulfillment
> for that need and communicating the fulfillment back to the client. GraphQL
> allows clients to ask for the exact data they need and makes it easier for
> servers to aggregate data from multiple data storage resources.

- GraphQL is a **query language** from which you can build APIs. It exists as an
  abstraction layer between a client that issues requests and a backend
  comprising any number of databases that responds to queries.
- Crucially, with applications that utilise GraphQL, both the backend and the
  frontend use the same GraphQL syntax. They speak the same language. This means
  that neither needs to take account of the way in which the other is
  implemented. For example, a client could request data from both a relational
  database and an object database without knowing there is any difference from
  its point of view. Conversely, client requests could be made through
  JavaScript or Python and the structure of the request received by the backend
  would be the same.
- The main benefit is its interoperability and its network economy when compared
  to REST APIs: you ask only for what you want and you get only that; there is
  no surplus data, increasing efficiency, reducing the number of network
  requests and reducing the size of the payload.

> The best way to think of GraphQL architecturally is to think of it as a
> different technique for instantiating the _uniform interface_, _client/server
> decoupling_, and _layered-system architecture_ contraints of traditional
> [REST APIs](RESTful_APIs.md#rest). However, instead of making
> GET or POST requests to a REST endpoint URL and passing parameters, you send a
> structured query object.

## Architecture

From the point of view of the frontend, GraphQL is a query language that may be
used via wrappers for a given framework or programming language (such as Apollo)
or directly simply by sending requests over HTTPS to a single URL.

From the point of view of the backend, GraphQL is a **runtime** that provides a
structure for servers to describe the data to be exposed in their APIs. We call
this structure the **schema**. For example, the GraphQL server might translate
the query into SQL statements for a relational database then take what the
storage engine responds with, translate it into JSON and send it back to the
client application.

> The backend implementation of GraphQL is known as the **GraphQL server**. This
> server is distinct from any of the physical servers that the backend may rely
> on. The client queries the GraphQL server.

Client requests are sent over HTTPS and the data is typically returned in the
form of JSON:

![](/img/graphql-architecture.png)

## Implementation overview

### Queries, mutations, subscriptions

Queries can be used for **both** reading and modifying data.

- When you need to read data with GraphQL you use **queries**
- When you need to modify data, you use **mutations**

So, for comparison, a query would be akin to a `READ` instruction in SQL or a
`GET` request send to a REST API. A mutation would be akin to `WRITE` then
`READ` instruction in SQL or a `POST` request to a REST API.

There is a third request type called a **subscription**. This is used for
real-time data monitoring requests, like a data stream, similar to a continuous
`READ` process. Mutations typically trigger events that can be subscribed to.

### Frontend

Below is an example of a request that would be made to a GraphQL server from the
frontend:

```graphql
query {
  employee(id: 42) {
    name
    email
  }
}
```

### Backend: structure and behaviour

We define the structure of a GraphQL API on the backend through the schema. A
schema is strongly typed and is basically a graph of fields that have types, e.g

```graphql
type Employee(id: Int!) {
  name: String!
  email: String!
}
```

`!` stands for required. In addition to the standard primitive data-types you
can also have custom types.

We implement the behaviour of the API through functions called **resolver
functions**. Each field in a GraphQL schema is backed by a resolver function. A
resolver function defines what data to fetch for its field.

> A resolver function represents the instructions on how and where to access raw
> data. For example, a resolver function might issue a SQL statement to a
> relational database, read a file’s data directly from the operating system, or
> update some cached data in a document database. A resolver function is
> directly related to a field in a GraphQL request, and it can represent a
> single primitive value, an object, or a list of values or objects.

### GraphQL endpoint

The GraphQL server exposes a single endpoint as a URL. This is in contrast to a
REST API where there are multiple endpoints, each corresponding to a different
resource. With GraphQL, the request is not specified by the URL and the payload
but rather in the GraphQL string that you send to the endpoint, like the
`employee` query above.

## Benefits

### Single requests

With a REST API if you require multiple resources you have to make multiple
requests to different endpoints and then once they resolve, synthesise them on
the client side. With GraphQL you can send a single request that encompasses
each individual resource:

The REST scenario:

![](/img/REST_request-load.png)

The GraphQL scenario:

![](/img/graphQL_request_load.png)

### Abstraction of multiple services

![](/img/graphql_multiple_resources.png)

### Stops overfetching

In a strict REST API you must request all resources from a given resource and
then filter on the client. With GraphQL you request only the resource you need
at the client-level.

### Single endpoint

In GraphQL you have a single endpoint and it always remains the same. This makes
updates easier to manage, since you don't need to broadcast new endpoints as the
API grows. It also simplifies frontend parsing, since you don't need to account
for, or interpolate different endpoints in your request URL.


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 $$


