# notes

path: zk/Ohms_Law.md
sortable_path: zkOhms_Law.md
title: Ohm's Law
checksum: d8bb6ce94a3a050e6f2494369e3a8fb2ae635a558fcf249321dd62a480ad4c31
created: 2024-03-30 09:03:20.493769503+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["physics","electricity"]}
lead:
  The relationship between
  [current](Current.md),
  [voltage](Voltage.md), and
  [resistance](Resistance.md) is
  defined by Ohm's Law:

body:
  The relationship between
  [current](Current.md),
  [voltage](Voltage.md), and
  [resistance](Resistance.md) is
  defined by Ohm's Law:

  > The current flowing from one point to another is equal to the voltage accross
  > these points divided by the resistance between them.

  $$
  I = \frac{V}{R}
  $$

  As an application, consider a circuit with a 9V battery with a 10,000 $\Omega$
  resistor attached across its terminals.

  The current flowing through the resistor can be calculated as follows:

  $$
  \frac{9V} {10,000\Omega} = 0.0009 \textsf{A} (0.9 \textsf{mA})
  $$

raw_content:
  ---
  tags: [physics, electricity]
  ---

  # Ohm's Law

  The relationship between
  [current](Current.md),
  [voltage](Voltage.md), and
  [resistance](Resistance.md) is
  defined by Ohm's Law:

  > The current flowing from one point to another is equal to the voltage accross
  > these points divided by the resistance between them.

  $$
  I = \frac{V}{R}
  $$

  As an application, consider a circuit with a 9V battery with a 10,000 $\Omega$
  resistor attached across its terminals.

  The current flowing through the resistor can be calculated as follows:

  $$
  \frac{9V} {10,000\Omega} = 0.0009 \textsf{A} (0.9 \textsf{mA})
  $$


path: zk/OpenSearch.md
sortable_path: zkOpenSearch.md
title: OpenSearch
lead: ## Background
checksum: d9fbc072965e3e5b5484e8077a808c28dc8740b7014912eda50b714a9ec80193
created: 2024-03-30 09:03:20.510995926+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["AWS"]}
body:
  ## Background

  OpenSearch is the AWS implementation of the opean source Elasticsearch search
  engine. It was formally known as "AWS Elasticsearch".

  It has many features but the core usage is to create searchable indicies of a
  given content domain such as, for example, a website or content management
  system. This enables the quick search and retrieval of documents without using
  expensive database queries.

  ## Key concepts

  We will introduce the main concepts with the example of an internal intranet for
  which we want to create a searchable index. The intranet comprises hundreds of
  pages. Each page has the following metadata, conforming to the following
  example.

  ```json
  {
    "title": "Internal News",
    "author": "Jane Doe",
    "published_date": "2023-11-01T00:00:00Z",
    "tags": ["news", "internal"],
    "categories": ["communication"],
    "content": "Today's internal news and updates are..."
  }
  ```

  ### Create domain

  The OpenSearch domain is a managed environment which hosts OpenSearch
  **clusters**. It can contain one or more clusters.

  The domain provides network **endpoints** you use to communicate and send
  requests. Typical requests:

  - ingest data
  - index data
  - run search query and return matches

  #### Clusters and nodes

  A cluster is the highest level of organisation within an OpensSearch domain that
  contains your indexed data. It processes all the search queries and handles
  tasks like indexing, searching, and managing documents.

  ![](/img/opensearch-architecture.drawio.svg)

  A cluster comprises **nodes**. Nodes are individual servers that hold part of
  the cluster's data. Each node participates in the indexing and searching of the
  cluster's data.

  - This distributed architecture helps in balancing the load and ensuring high
    availability.
  - Data can be replicated accross nodes, making the system resiliant against data
    loss
  - You can add more nodes to the cluster to handle increased data and traffic,
    making the system adaptable to changing needs.

  ### Define index and mappings

  Assuming the domain has been created. The next step is to create an index for
  the data, say `intranet_pages`. An index is basically a collection where the
  data is stored, similar to a database. Each entry is a **document** in this
  collection.

  Our index will store each webpage as a document.

  We specify the data that we want to store using an index mapping. For instance
  we may not want to store all the metadata for each page, preferring only to
  index a subset of the properties. In this example we will store all the data. We
  would achieve this with the following:

  ```json
  {
    "mappings": {
      "properties": {
        "title": { "type": "text" },
        "author": { "type": "keyword" },
        "published_date": { "type": "date" },
        "tags": { "type": "keyword" },
        "content": { "type": "text" }
      }
    }
  }
  ```

  The mapping will be utilised in the following scenarios:

  - storing data:
    - when a new document is added to the `intranet_pages` index, it will adhere
      to the defined mappings
    - it will have to have the properties specified in the mapping in order to be
      added
  - searching data:
    - when executing searches, OpenSearch utilizes the mappings to understand the
      type of data in each field and optimizes search queries accordingly
  - assessing relevance:
    - proper mappings allow OpenSearch to accurately score and rank search results
      based on relevance.

  ### Ingest data (bulk import and/or scraper)

  In order to create the index that we previously defined with a mapping it is
  necessary to implement some sort of mechanism for collating the metadata that
  matches the mapping. This would be a crawler or scraper that might be
  implemented with a lambda. This is a key part of the ingestion process.

  Alternatively the data could be bulk imported in a format that maps to the
  index.

  ### Querying and searching

  Having established the crawler (and some kind of search interface), we can now
  run queries against the OpenSearch domain.

  A basic example of the structure of a query would be as follows:

  ```sh
  GET /intranet_pages/_search
  ```

  ```json
  {
    "query": {
      "match": {
        "content": "project"
      }
    }
  }
  ```

  Here we search against the `content` mapping to find pages that contain the word
  "project".

  Example of the data returned:

  ```json
  {
    "hits": {
      "total": { "value": 100 },
      "hits": [
        {
          "_index": "intranet_pages",
          "_id": "1",
          "_score": 1.2,
          "_source": {
            "title": "Project ABC Launch",
            "author": "John Doe",
            "published_date": "2023-01-01T00:00:00Z",
            "tags": ["project", "launch"],
            "content": "Details about the launch of Project ABC..."
          }
        }
        // Additional results here
      ]
    }
  }
  ```

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

  Find documents that are authored by Jane Doe that contain the word "meeting".
  `must` stands for boolean AND:

  ```json
  {
    "query": {
      "bool": {
        "must": [
          { "match": { "content": "meeting" } },
          { "match": { "author": "Jane Doe" } }
        ]
      }
    }
  }
  ```

  Find documents that contain either the word "meeting" or the word "project" in
  their content. `should` stands for boolean OR:

  ```json
  {
    "query": {
      "bool": {
        "should": [
          { "match": { "content": "meeting" } },
          { "match": { "content": "project" } }
        ],
        "minimum_should_match": 1
      }
    }
  }
  ```

  `minimum_should_match` specifies the number of conditions that should match.

  ### Query by date ranges

  Find pages published after a certain date:

  ```json
  {
    "query": {
      "range": {
        "published_date": {
          "gte": "2023-01-01T00:00:00Z"
        }
      }
    }
  }
  ```

  ```json
  {
    "query": {
      "bool": {
        "should": [
          { "match": { "fileId": "val" } },
          { "match": { "programmeId": "val" } },
          { "match": { "guid": "val" } }
        ],
        "minimum_should_match": 1
      }
    }
  }
  ```

raw_content:
  ---
  tags: [AWS]
  ---

  # OpenSearch

  ## Background

  OpenSearch is the AWS implementation of the opean source Elasticsearch search
  engine. It was formally known as "AWS Elasticsearch".

  It has many features but the core usage is to create searchable indicies of a
  given content domain such as, for example, a website or content management
  system. This enables the quick search and retrieval of documents without using
  expensive database queries.

  ## Key concepts

  We will introduce the main concepts with the example of an internal intranet for
  which we want to create a searchable index. The intranet comprises hundreds of
  pages. Each page has the following metadata, conforming to the following
  example.

  ```json
  {
    "title": "Internal News",
    "author": "Jane Doe",
    "published_date": "2023-11-01T00:00:00Z",
    "tags": ["news", "internal"],
    "categories": ["communication"],
    "content": "Today's internal news and updates are..."
  }
  ```

  ### Create domain

  The OpenSearch domain is a managed environment which hosts OpenSearch
  **clusters**. It can contain one or more clusters.

  The domain provides network **endpoints** you use to communicate and send
  requests. Typical requests:

  - ingest data
  - index data
  - run search query and return matches

  #### Clusters and nodes

  A cluster is the highest level of organisation within an OpensSearch domain that
  contains your indexed data. It processes all the search queries and handles
  tasks like indexing, searching, and managing documents.

  ![](/img/opensearch-architecture.drawio.svg)

  A cluster comprises **nodes**. Nodes are individual servers that hold part of
  the cluster's data. Each node participates in the indexing and searching of the
  cluster's data.

  - This distributed architecture helps in balancing the load and ensuring high
    availability.
  - Data can be replicated accross nodes, making the system resiliant against data
    loss
  - You can add more nodes to the cluster to handle increased data and traffic,
    making the system adaptable to changing needs.

  ### Define index and mappings

  Assuming the domain has been created. The next step is to create an index for
  the data, say `intranet_pages`. An index is basically a collection where the
  data is stored, similar to a database. Each entry is a **document** in this
  collection.

  Our index will store each webpage as a document.

  We specify the data that we want to store using an index mapping. For instance
  we may not want to store all the metadata for each page, preferring only to
  index a subset of the properties. In this example we will store all the data. We
  would achieve this with the following:

  ```json
  {
    "mappings": {
      "properties": {
        "title": { "type": "text" },
        "author": { "type": "keyword" },
        "published_date": { "type": "date" },
        "tags": { "type": "keyword" },
        "content": { "type": "text" }
      }
    }
  }
  ```

  The mapping will be utilised in the following scenarios:

  - storing data:
    - when a new document is added to the `intranet_pages` index, it will adhere
      to the defined mappings
    - it will have to have the properties specified in the mapping in order to be
      added
  - searching data:
    - when executing searches, OpenSearch utilizes the mappings to understand the
      type of data in each field and optimizes search queries accordingly
  - assessing relevance:
    - proper mappings allow OpenSearch to accurately score and rank search results
      based on relevance.

  ### Ingest data (bulk import and/or scraper)

  In order to create the index that we previously defined with a mapping it is
  necessary to implement some sort of mechanism for collating the metadata that
  matches the mapping. This would be a crawler or scraper that might be
  implemented with a lambda. This is a key part of the ingestion process.

  Alternatively the data could be bulk imported in a format that maps to the
  index.

  ### Querying and searching

  Having established the crawler (and some kind of search interface), we can now
  run queries against the OpenSearch domain.

  A basic example of the structure of a query would be as follows:

  ```sh
  GET /intranet_pages/_search
  ```

  ```json
  {
    "query": {
      "match": {
        "content": "project"
      }
    }
  }
  ```

  Here we search against the `content` mapping to find pages that contain the word
  "project".

  Example of the data returned:

  ```json
  {
    "hits": {
      "total": { "value": 100 },
      "hits": [
        {
          "_index": "intranet_pages",
          "_id": "1",
          "_score": 1.2,
          "_source": {
            "title": "Project ABC Launch",
            "author": "John Doe",
            "published_date": "2023-01-01T00:00:00Z",
            "tags": ["project", "launch"],
            "content": "Details about the launch of Project ABC..."
          }
        }
        // Additional results here
      ]
    }
  }
  ```

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

  Find documents that are authored by Jane Doe that contain the word "meeting".
  `must` stands for boolean AND:

  ```json
  {
    "query": {
      "bool": {
        "must": [
          { "match": { "content": "meeting" } },
          { "match": { "author": "Jane Doe" } }
        ]
      }
    }
  }
  ```

  Find documents that contain either the word "meeting" or the word "project" in
  their content. `should` stands for boolean OR:

  ```json
  {
    "query": {
      "bool": {
        "should": [
          { "match": { "content": "meeting" } },
          { "match": { "content": "project" } }
        ],
        "minimum_should_match": 1
      }
    }
  }
  ```

  `minimum_should_match` specifies the number of conditions that should match.

  ### Query by date ranges

  Find pages published after a certain date:

  ```json
  {
    "query": {
      "range": {
        "published_date": {
          "gte": "2023-01-01T00:00:00Z"
        }
      }
    }
  }
  ```

  ```json
  {
    "query": {
      "bool": {
        "should": [
          { "match": { "fileId": "val" } },
          { "match": { "programmeId": "val" } },
          { "match": { "guid": "val" } }
        ],
        "minimum_should_match": 1
      }
    }
  }
  ```


path: zk/Order_of_operations.md
sortable_path: zkOrder_of_operations.md
lead:
  ---
  tags:
  - prealgebra
  ---

checksum: 22b182e2b1de87fa63fc85630a6ea75a783842c449ca5cde022f417450197adc
created: 2024-03-30 09:03:20.515968282+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["prealgebra"]}
body:
  ---
  tags:
    - prealgebra
  ---

  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
  ```

raw_content:
  ---
  tags:
    - prealgebra
  ---

  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
  ```


path: zk/Package_management.md
sortable_path: zkPackage_management.md
title: Package management
lead: ## List installed packages
checksum: a4752920727fecb5b8ce97d7572b92652a86d679349fb8b71c6d9695790bc888
created: 2024-03-30 09:03:20.520292932+00:00
modified: 2024-06-15 09:50:35.966759132+00:00
metadata: {"tags":["node-js"]}
body:
  ## 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).

raw_content:
  ---
  tags:
    - node-js
  ---

  # 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).


path: zk/Pacman.md
sortable_path: zkPacman.md
title: Pacman
lead: ## List all installed packages
checksum: 96f61c72f6526b9934d20af83561c7fa3d8bc01efba1984f5f792ddc7d0451f6
created: 2024-03-30 09:03:20.530540885+00:00
modified: 2024-03-28 13:31:29.771829848+00:00
metadata: {"tags":[]}
body:
  ## List all installed packages

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

  ## Uninstall, and list dependencies for package to be uninstalled

  ```
  pacman -Rcns
  ```

raw_content:
  ---
  tags: []
  ---

  # Pacman

  ## List all installed packages

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

  ## Uninstall, and list dependencies for package to be uninstalled

  ```
  pacman -Rcns
  ```


path: zk/Passing_arguments_and_options_to_Bash_scripts.md
sortable_path: zkPassing_arguments_and_options_to_Bash_scripts.md
title: Passing arguments and options to Bash scripts
lead: ## Relation between commands and programs
checksum: 6556e370417eac93215b75f6ced2cd075840bb80b8cb644530db26e18760bae8
created: 2024-03-30 09:03:20.559218792+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ## 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

  ```

raw_content:
  ---
  tags:
    - shell
  ---

  # 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

  ```


path: zk/Ports.md
sortable_path: zkPorts.md
title: Ports
checksum: c9975673e974869e0d02f1f89f50d66c63960e6cdd9b0af1d6d5912241e71bb3
created: 2024-03-30 09:03:20.5676326+00:00
modified: 2024-06-15 09:50:38.086800108+00:00
metadata: {"tags":["node-js"]}
lead:
  When working in development we are able to specify the specific port from which
  we want top serve our application. In production, we do not always have this
  control: the port will most likely be set by the provider of the server
  environment.

body:
  When working in development we are able to specify the specific port from which
  we want top serve our application. In production, we do not always have this
  control: the port will most likely be set by the provider of the server
  environment.

  While we may not know the specific port, whatever it is, it will be accessible
  via the `PORT` environment variable. So we can use this when writing our
  [event listeners](Events%20module.md#event-emitters):

  ```js
  const port = process.env.PORT || 3000;
  ```

  This way, if a port is set by the provider it will use it. If not, it will fall
  back to 3000.

raw_content:
  ---
  tags:
    - node-js
  ---

  # Ports

  When working in development we are able to specify the specific port from which
  we want top serve our application. In production, we do not always have this
  control: the port will most likely be set by the provider of the server
  environment.

  While we may not know the specific port, whatever it is, it will be accessible
  via the `PORT` environment variable. So we can use this when writing our
  [event listeners](Events%20module.md#event-emitters):

  ```js
  const port = process.env.PORT || 3000;
  ```

  This way, if a port is set by the provider it will use it. If not, it will fall
  back to 3000.


path: zk/Practical_walkthrough_Lambda_creation_within_AWS.md
sortable_path: zkPractical_walkthrough_Lambda_creation_within_AWS.md
title: Practical walkthrough of creating a Lambda function via the AWS Management Console
lead: ## Basic set-up
checksum: 8aaa595a4ee06aa4eaf98a9d65d0034ff5b0f795fe36d42fe503ee3453f7c696
created: 2024-03-30 09:03:20.578995245+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS","aws-lambda","node-js"]}
body:
  ## Basic set-up

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

  This presents us with the function dashboard - a graphical representation of the
  Lambda showing [triggers]() as an input and destination as an output:

  ![](/img/lambda-func-two.png)

  Beneath this we have a code editor with the handler function with a basic
  boilerplate:

  ![](/img/lambda-func-three.png)

  ## Adding a trigger

  Next we need to add a [trigger](Lambda_triggers.md) that
  execute the handler.

  We will do this using [AWS API Gateway](AWS_API_Gateway.md). We
  select "Add trigger" from the dashboard view and input basic settings:

  ![](/img/api-gateway-trigger.png)

  Now we see this step displayed in the dashboard:

  ![](/img/lambda-overview.png)

  With the endpoint and other settings displayed:

  ![](/img/trigger-info.png)

  If we go to the endpoint URL
  (`https://4kjqwbvd7g.execute-api.us-east-1.amazonaws.com/default/myFirstFunction`),
  we will see the output: `Hello from Lambda`.

  ## Handling parameters

  We can make the example more realistic by expanding the handler to accept query
  parameters. We do this by accessing the value `queryStringParameters` on the
  `event` object:

  ```js
  exports.handler = async (event) => {
    const name = event.queryStringParameters && event.queryStringParameters.name;

    let message = "Hello Lambda";

    if (name !== null) {
      message = `Hello ${name}`;
    }

    const response {
      statusCode: 200,
      body: JSON.stringify(message)

    }
  };
  ```

  If we now access
  `https://4kjqwbvd7g.execute-api.us-east-1.amazonaws.com/default/myFirstFunction?name=Thomas`

  We get `Hello Thomas` as output.

  For a more advanced API with multiple endpoints and parameters, it's easiest to
  use Postman:

  ![](/img/postman-lambda.png)

raw_content:
  ---
  tags: [AWS, aws-lambda, node-js]
  ---

  # Practical walkthrough of creating a Lambda function via the AWS Management Console

  ## Basic set-up

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

  This presents us with the function dashboard - a graphical representation of the
  Lambda showing [triggers]() as an input and destination as an output:

  ![](/img/lambda-func-two.png)

  Beneath this we have a code editor with the handler function with a basic
  boilerplate:

  ![](/img/lambda-func-three.png)

  ## Adding a trigger

  Next we need to add a [trigger](Lambda_triggers.md) that
  execute the handler.

  We will do this using [AWS API Gateway](AWS_API_Gateway.md). We
  select "Add trigger" from the dashboard view and input basic settings:

  ![](/img/api-gateway-trigger.png)

  Now we see this step displayed in the dashboard:

  ![](/img/lambda-overview.png)

  With the endpoint and other settings displayed:

  ![](/img/trigger-info.png)

  If we go to the endpoint URL
  (`https://4kjqwbvd7g.execute-api.us-east-1.amazonaws.com/default/myFirstFunction`),
  we will see the output: `Hello from Lambda`.

  ## Handling parameters

  We can make the example more realistic by expanding the handler to accept query
  parameters. We do this by accessing the value `queryStringParameters` on the
  `event` object:

  ```js
  exports.handler = async (event) => {
    const name = event.queryStringParameters && event.queryStringParameters.name;

    let message = "Hello Lambda";

    if (name !== null) {
      message = `Hello ${name}`;
    }

    const response {
      statusCode: 200,
      body: JSON.stringify(message)

    }
  };
  ```

  If we now access
  `https://4kjqwbvd7g.execute-api.us-east-1.amazonaws.com/default/myFirstFunction?name=Thomas`

  We get `Hello Thomas` as output.

  For a more advanced API with multiple endpoints and parameters, it's easiest to
  use Postman:

  ![](/img/postman-lambda.png)


path: zk/Prefixes_for_units_of_electrical_measurement.md
sortable_path: zkPrefixes_for_units_of_electrical_measurement.md
title: Prefixes for unit of electrical measurement
checksum: 8862db3b8a39d32e027c6882099e701167c87d7d3d07d136fba4c0ad18720de3
created: 2024-03-30 09:03:20.591067186+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["physics","electricity","exponents"]}
lead:
  In electronics we are often dealing with units that are very large or very
  small, thus we rely on [exponents](Exponents.md) for formal
  expression.

body:
  In electronics we are often dealing with units that are very large or very
  small, thus we rely on [exponents](Exponents.md) for formal
  expression.

  | Prefix | Symbol | Expression as exponent | Expression as decimal value | English word |
  | ------ | ------ | ---------------------- | --------------------------- | ------------ |
  | Terra- | T      | $10^{12}$              | 1,000,000,000,000           | trillion     |
  | Giga-  | G      | $10^9$                 | 1,000,000,000               | billion      |
  | Mega-  | M      | $10^6$                 | 1,000,000                   | million      |
  | Kilo-  | k      | $10^3$                 | 1,000                       | thousand     |
  | Centi- | c      | $10^{-2}$              | 0.01                        | hundredth    |
  | Milli- | m      | $10^{-3}$              | 0.001                       | thousandth   |
  | Micro- | $\mu$  | $10^{-6}$              | 0.0000001                   | millionth    |
  | Nano-  | n      | $10^{-9}$              | 0.0000000001                | billionth    |
  | Pico-  | p      | $10^{-12}$             | 0.0000000000001             | trillionth   |

  For example, with Amps we tend not to use 1 whole amp as this is far too large
  for most electronics. More common is the milliampere (mA) and the microampere
  ($\mu$A).

  A mA is equal to one thousandth of an ampere: 0.001 A. It takes 1000
  milliamperes to equal one ampere.

  A $\mu$A is equal to one millionth of an ampere: 0.0000001 A. It takes one
  million micoramperes to equal one ampere.

raw_content:
  ---
  tags: [physics, electricity, exponents]
  ---

  # Prefixes for unit of electrical measurement

  In electronics we are often dealing with units that are very large or very
  small, thus we rely on [exponents](Exponents.md) for formal
  expression.

  | Prefix | Symbol | Expression as exponent | Expression as decimal value | English word |
  | ------ | ------ | ---------------------- | --------------------------- | ------------ |
  | Terra- | T      | $10^{12}$              | 1,000,000,000,000           | trillion     |
  | Giga-  | G      | $10^9$                 | 1,000,000,000               | billion      |
  | Mega-  | M      | $10^6$                 | 1,000,000                   | million      |
  | Kilo-  | k      | $10^3$                 | 1,000                       | thousand     |
  | Centi- | c      | $10^{-2}$              | 0.01                        | hundredth    |
  | Milli- | m      | $10^{-3}$              | 0.001                       | thousandth   |
  | Micro- | $\mu$  | $10^{-6}$              | 0.0000001                   | millionth    |
  | Nano-  | n      | $10^{-9}$              | 0.0000000001                | billionth    |
  | Pico-  | p      | $10^{-12}$             | 0.0000000000001             | trillionth   |

  For example, with Amps we tend not to use 1 whole amp as this is far too large
  for most electronics. More common is the milliampere (mA) and the microampere
  ($\mu$A).

  A mA is equal to one thousandth of an ampere: 0.001 A. It takes 1000
  milliamperes to equal one ampere.

  A $\mu$A is equal to one millionth of an ampere: 0.0000001 A. It takes one
  million micoramperes to equal one ampere.


path: zk/Prime_factorization.md
sortable_path: zkPrime_factorization.md
title: Prime factorisation
checksum: 11bafeef8c6f1f1dc3cb5fbb5977584a6326c723fb5f5980248e086a186e11a4
created: 2024-03-30 09:03:20.597398285+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","number-theory"]}
lead:
  Prime factorisation is the activity of expressing a composite number as the
  unique product of [prime numbers](Primes%20and%20composites.md). There are two
  main approaches to this:

body:
  Prime factorisation is the activity of expressing a composite number as the
  unique product of [prime numbers](Primes%20and%20composites.md). There are two
  main approaches to this:

  - - factor\* trees
  - repeated division by two

  > **Factor trees:** we take a number $n$ and break it down into two factors of
  > $n$. We then repeat this process with the resulting factors working
  > recursively until the numbers we are left with are primes.

  ![Untitled Diagram-Page-1.drawio.png](Untitled%20Diagram-Page-1.drawio.png)
  _The prime factors of 27 are 2, 3, 3_

  it doesn't matter which products we choose as the interim factors, we should
  always reach the same outcome:
  ![Untitled Diagram-Page-3.drawio 1.png](Untitled%20Diagram-Page-3.drawio%201.png)

  ![Untitled Diagram-Page-2.drawio.png](Untitled%20Diagram-Page-2.drawio.png)

raw_content:
  ---
  tags:
    - prealgebra
    - number-theory
  ---

  ### Prime factorisation

  Prime factorisation is the activity of expressing a composite number as the
  unique product of [prime numbers](Primes%20and%20composites.md). There are two
  main approaches to this:

  - - factor\* trees
  - repeated division by two

  > **Factor trees:** we take a number $n$ and break it down into two factors of
  > $n$. We then repeat this process with the resulting factors working
  > recursively until the numbers we are left with are primes.

  ![Untitled Diagram-Page-1.drawio.png](Untitled%20Diagram-Page-1.drawio.png)
  _The prime factors of 27 are 2, 3, 3_

  it doesn't matter which products we choose as the interim factors, we should
  always reach the same outcome:
  ![Untitled Diagram-Page-3.drawio 1.png](Untitled%20Diagram-Page-3.drawio%201.png)

  ![Untitled Diagram-Page-2.drawio.png](Untitled%20Diagram-Page-2.drawio.png)


path: zk/Primes_and_composites.md
sortable_path: zkPrimes_and_composites.md
title: Prime and composite numbers
lead: Definition of a **prime number**:
checksum: 084d62e611aa66271096191f460ece84ec7824736295b5e16f5d3dbcc7ab8cef
created: 2024-03-30 09:03:20.608935468+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","number-theory"]}
body:
  Definition of a **prime number**:

  > For any whole number $n$ where $n \neq 1$, $n$ is prime if and only if its
  > sole [factors](Factors%20and%20divisors.md) are $1$ and $n$

  Definition of a **composite number**:

  > For any whole number $n$, $n$ is composite just if $n$ is not prime

raw_content:
  ---
  tags:
    - prealgebra
    - number-theory
  ---

  ## Prime and composite numbers

  Definition of a **prime number**:

  > For any whole number $n$ where $n \neq 1$, $n$ is prime if and only if its
  > sole [factors](Factors%20and%20divisors.md) are $1$ and $n$

  Definition of a **composite number**:

  > For any whole number $n$, $n$ is composite just if $n$ is not prime


path: zk/Primitive_types.md
sortable_path: zkPrimitive_types.md
title: Primitive types
checksum: 7e5afd3f7ab27ed61d7a12981598ff65f25a1a0bb6df6d01636b5b2332f9d00d
created: 2024-03-30 09:03:20.62007709+00:00
modified: 2024-06-16 16:59:59.6481695+00:00
metadata: {"tags":["typescript","data-types"]}
lead:
  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

body:
  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[] = [{}, ...]

  ```

raw_content:
  ---
  tags:
    - typescript
    - data-types
  ---

  # 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[] = [{}, ...]

  ```


path: zk/Processes.md
sortable_path: zkProcesses.md
title: Processes (ps)
lead:
  `ps` allows us to control [user processes](The_Kernel.md)
  from the shell.

checksum: a858d422a2c60511512a28ed9bac6959e67c830b44a0da55b571326917c19bf5
created: 2024-03-30 09:03:20.629874277+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  `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`

raw_content:
  ---
  tags:
    - shell
  ---

  # 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`


path: zk/Prop_types.md
sortable_path: zkProp_types.md
title: Prop types
checksum: 727c77a483cc8cd4beceb26f9145e1f40aef386f77b3ac6c2f4b43d874e30039
created: 2024-03-30 09:03:20.640858185+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","react","data-types"]}
lead:
  **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.**

body:
  **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),
  ```

raw_content:
  ---
  tags:
    - javascript
    - react
    - data-types
  ---

  # 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),
  ```


path: zk/Proper_shebang_syntax.md
sortable_path: zkProper_shebang_syntax.md
title: Proper shebang syntax
checksum: edcb7998f0254eab27ba5419de171e27c3a25fc8f6863e4021a0bbb4a4fbbece
created: 2024-03-30 09:03:20.645741491+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
lead:
  This is a more portable way of writing the shebang because the location of Bash
  on different systems can vary.

body:
  This is a more portable way of writing the shebang because the location of Bash
  on different systems can vary.

  ```bash
  #!/usr/bin/env Bash
  ```

  Rather than:

  ```bash
  #!/bin/bash
  ```

raw_content:
  ---
  tags:
    - shell
  ---

  # Proper shebang syntax

  This is a more portable way of writing the shebang because the location of Bash
  on different systems can vary.

  ```bash
  #!/usr/bin/env Bash
  ```

  Rather than:

  ```bash
  #!/bin/bash
  ```


path: zk/Props.md
sortable_path: zkProps.md
title: Props
lead: ## Types or interfaces?
checksum: 5932443b8d7abf3608aa338b3410754fc1976a0a2fc49a45a3a865dba90389b0
created: 2024-03-30 09:03:20.649913083+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["typescript","react"]}
body:
  ## Types or interfaces?

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

  - Classes and other interfaces can extend an interface but not a type

    ```ts
    interface Animal {
      name: string;
    }

    interface Bear extends Animal {
      honey: boolean;
    }
    ```

  - You can add properties to an interface without generating a double declaration
    error:

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

  > The consensus seems to be that interfaces should be used over types unless
  > there are ocassions when you do not want a type to be extendable /
  > redeclarable. Or when you want to use unions.

  ## How we type props

  The custom is to type props as an interface. This way we can easily type
  function prop types.

  ```tsx
  interface IProps {
    people: {
      name: string;
      age: number;
      note?: string;
    }[];
  }

  const List: React.FC<IProps> = ({people}: IProps) => {
      return()
  }

  // Note we say that the props into the func component are of type IProps
  // And we destructure the people key

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

  ```tsx
  interface IProps {
    obj: {};
  }
  ```

  ### Array of objects

  ```tsx
  interface IProps {
    val1: string;
    val2: boolean;
  }
  [];
  ```

  ### Functions

  ```tsx

  // Function that doesn't receive or return anything
  interface IProps {
      onClick: () => void;
  }[]

  // Function with named parameter
  interface IProps {
      onClick: (id: number) => void;
  }[]

  // Function that takes an event
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  ```

  ### Other React components

  ```js
  interface IProps {
    children: React.ReactNode;
  }

  interface IProps {
    children: JSX.Element;
  }
  ```

  `React.ReactNode` covers everything that React can render. This should be
  definitely used when the prop is a child component, otherwise `JSX.element` is
  ok.

  <p style="color: red;">Should I use type or interface? What is consensus?</p>

raw_content:
  ---
  tags:
    - typescript
    - react
  ---

  # Props

  ## Types or interfaces?

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

  - Classes and other interfaces can extend an interface but not a type

    ```ts
    interface Animal {
      name: string;
    }

    interface Bear extends Animal {
      honey: boolean;
    }
    ```

  - You can add properties to an interface without generating a double declaration
    error:

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

  > The consensus seems to be that interfaces should be used over types unless
  > there are ocassions when you do not want a type to be extendable /
  > redeclarable. Or when you want to use unions.

  ## How we type props

  The custom is to type props as an interface. This way we can easily type
  function prop types.

  ```tsx
  interface IProps {
    people: {
      name: string;
      age: number;
      note?: string;
    }[];
  }

  const List: React.FC<IProps> = ({people}: IProps) => {
      return()
  }

  // Note we say that the props into the func component are of type IProps
  // And we destructure the people key

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

  ```tsx
  interface IProps {
    obj: {};
  }
  ```

  ### Array of objects

  ```tsx
  interface IProps {
    val1: string;
    val2: boolean;
  }
  [];
  ```

  ### Functions

  ```tsx

  // Function that doesn't receive or return anything
  interface IProps {
      onClick: () => void;
  }[]

  // Function with named parameter
  interface IProps {
      onClick: (id: number) => void;
  }[]

  // Function that takes an event
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  ```

  ### Other React components

  ```js
  interface IProps {
    children: React.ReactNode;
  }

  interface IProps {
    children: JSX.Element;
  }
  ```

  `React.ReactNode` covers everything that React can render. This should be
  definitely used when the prop is a child component, otherwise `JSX.element` is
  ok.

  <p style="color: red;">Should I use type or interface? What is consensus?</p>


path: zk/Prototypical_inheritance.md
sortable_path: zkPrototypical_inheritance.md
title: Prototypical inheritance
lead: ## Object oriented basis of JavaScript and nomenclature
checksum: b332dfadb655c7db9d31679a6ca1dc695fef44a404f9abc92e05b34c43b517a7
created: 2024-03-30 09:03:20.655417991+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","OOP"]}
body:
  ## 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.

raw_content:
  ---
  tags: [javascript, OOP]
  ---

  # 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.


path: zk/Python_data_types.md
sortable_path: zkPython_data_types.md
title: Python data-types
checksum: 87a8e9b94c5a6050161b68234964ee99022aef37f835f759d55a650977ba7b2f
created: 2024-03-30 09:03:20.659578738+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-types"]}
lead:
  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

body:
  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

  The core data-types are as follows:

  - [str](Strings_in_Python.md)
  - bool
  - float
  - double

  We can identify types using the built-in `type()` function:

  ```python
  # Integer number
  my_variable = 422
  print(my_variable)
  print(type(my_variable))
  # <class 'int'>

  # String type
  my_variable = 'Natalia'
  print(my_variable)
  print(type(my_variable))
  # <class 'str'>

  # Boolean type
  my_variable = True
  print(my_variable)
  print(type(my_variable))
  # <class 'bool'>
  ```

  ## Converting data-types

  For every data-type there is a corresponding converter method, e.g:

  ```python
  a_string = '32'
  print(f'a_string {a_string} is {type(a_string)}')
  an_int = int(a_string)

  print(f'an_int {a_string} is {type(an_int)}')
  a_float = float(a_string)

  print(f'a_float {a_string} is {type(a_float)}')
  another_string = str(42)

  print(f'another_string {a_string} is {type(another_string)}')
  ```

raw_content:
  ---
  tags: [python, data-types]
  ---

  # Python data-types

  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

  The core data-types are as follows:

  - [str](Strings_in_Python.md)
  - bool
  - float
  - double

  We can identify types using the built-in `type()` function:

  ```python
  # Integer number
  my_variable = 422
  print(my_variable)
  print(type(my_variable))
  # <class 'int'>

  # String type
  my_variable = 'Natalia'
  print(my_variable)
  print(type(my_variable))
  # <class 'str'>

  # Boolean type
  my_variable = True
  print(my_variable)
  print(type(my_variable))
  # <class 'bool'>
  ```

  ## Converting data-types

  For every data-type there is a corresponding converter method, e.g:

  ```python
  a_string = '32'
  print(f'a_string {a_string} is {type(a_string)}')
  an_int = int(a_string)

  print(f'an_int {a_string} is {type(an_int)}')
  a_float = float(a_string)

  print(f'a_float {a_string} is {type(a_float)}')
  another_string = str(42)

  print(f'another_string {a_string} is {type(another_string)}')
  ```


path: zk/Python_execution.md
sortable_path: zkPython_execution.md
title: Python execution
lead: For immediately executable scripts, we have to have a Python shebang at the top:
checksum: 30db233c5b46a73df2c5ab204f80b8f28ab8e94586db8ea06e7bcbe8cb0c090c
created: 2024-03-30 09:03:20.670131186+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-types"]}
body:
  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`.

raw_content:
  ---
  tags: [python, data-types]
  ---

  # 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`.


path: zk/Python_interpreter.md
sortable_path: zkPython_interpreter.md
title: Python interpreter
lead: ## What is an implementation of a programming language?
checksum: 76b7b7c27f575074f2e906518a4155469c62525b955059dce6f9d22f5e9046eb
created: 2024-03-30 09:03:20.674800238+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python"]}
body:
  ## What is an implementation of a programming language?

  An implementation of Python:

  > means a program or environment which provides support for the execution of
  > programs written in the Python language

  As Python is interpreted, any implementation will perforce involve an
  interpreting language.

  There are three main implementations:

  - CPython
    - The default implementation, written in C
  - Jython
    - Python implemented by Java and running on the JVM
  - PyPy
    - A subset of Python which is faster due to machine code compilation

  ## CPython

  In the standard implementation, the language which interprets Python code is C.

  When Python runs in this implementation, code written in C converts it to
  bytecode (so-called because each instruction is
  [8-bits long](Binary_units_of_measurement.md)). This is a
  lower-level transliteration of Python is not meant to be understood by the CPU
  (since it is not binary) but rather to be run in the Python virtual machine
  which is equipped to understand bytecode. The Python Virtual Machine is
  therefore also known as "bytecode interpreter" or the CPython VM. The VM then
  converts bytecode into machine-executable code.

  The fact that Python does not compile to binary means that it can run on a
  greater variety of hardwares however it is slower than a language that compiles
  to machine code. PyPy is a solution for this because it is both interpreted and
  compiled to optimised machine code at run time.

  Where CPython is the interpreter, Python extensions can be written in C.

  ## PyPy

  PyPy is an alternative implementation to CPython. The main difference is that it
  uses a JIT-compiler and doesn't convert Python to the intermediary byte code. It
  is also written in Python itself, specifically RPython ('restricted Python').
  This is capable of converting Python directly to machine code without the
  CPython virtual machine.

  ## Jython

  Jython is an implementation of Python written in Java. Like CPython it converts
  Python to bytecode but this runs on the JVM. As it is written in Java, a Jython
  program can import and use any Java class.

  Where Jython is the interpreter, Python extension can be written in Java.

raw_content:
  ---
  tags: [python]
  ---

  # Python interpreter

  ## What is an implementation of a programming language?

  An implementation of Python:

  > means a program or environment which provides support for the execution of
  > programs written in the Python language

  As Python is interpreted, any implementation will perforce involve an
  interpreting language.

  There are three main implementations:

  - CPython
    - The default implementation, written in C
  - Jython
    - Python implemented by Java and running on the JVM
  - PyPy
    - A subset of Python which is faster due to machine code compilation

  ## CPython

  In the standard implementation, the language which interprets Python code is C.

  When Python runs in this implementation, code written in C converts it to
  bytecode (so-called because each instruction is
  [8-bits long](Binary_units_of_measurement.md)). This is a
  lower-level transliteration of Python is not meant to be understood by the CPU
  (since it is not binary) but rather to be run in the Python virtual machine
  which is equipped to understand bytecode. The Python Virtual Machine is
  therefore also known as "bytecode interpreter" or the CPython VM. The VM then
  converts bytecode into machine-executable code.

  The fact that Python does not compile to binary means that it can run on a
  greater variety of hardwares however it is slower than a language that compiles
  to machine code. PyPy is a solution for this because it is both interpreted and
  compiled to optimised machine code at run time.

  Where CPython is the interpreter, Python extensions can be written in C.

  ## PyPy

  PyPy is an alternative implementation to CPython. The main difference is that it
  uses a JIT-compiler and doesn't convert Python to the intermediary byte code. It
  is also written in Python itself, specifically RPython ('restricted Python').
  This is capable of converting Python directly to machine code without the
  CPython virtual machine.

  ## Jython

  Jython is an implementation of Python written in Java. Like CPython it converts
  Python to bytecode but this runs on the JVM. As it is written in Java, a Jython
  program can import and use any Java class.

  Where Jython is the interpreter, Python extension can be written in Java.


path: zk/Python_modules_and_imports.md
sortable_path: zkPython_modules_and_imports.md
title: Python modules
lead: ## Distinguishing _modules_ from _packages_
checksum: c8d45e1dabc5ec3c2d533fd819b72a8b38b47d7f12b3614dc0e4c5e3835581d2
created: 2024-03-30 09:03:20.683171526+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","OOP"]}
body:
  ## Distinguishing _modules_ from _packages_

  Modules and packages in Python are very similar to modules in Node.js: a
  combination of several pieces of functionality (often written in a mix of
  different syntactic styles) bundled together to be used as a unit.

  - A **module** is basically just a script - a single Python file that you can
    import using the `import` statement
  - A **package** is a _collection of modules_

  A package is a whole directory which has an `__init__.py` at its root which
  designates it as a package (this can be empty, but it is necessary to have this
  file for the interpreter to understand that the directory is a package).

  ## Creating modules

  ### Naming modules

  The name of a module is the name of its file, e.g. `utils.py` defines the module
  `utils`. When we import a module we do not need to specify the extension.

  ### Example module

  Here is an example of a module.

  ```py
  """utils module"""

  print('Hello I am the utils module')


  def printer(some_object):
      print('printer')
      print(some_object)
      print('done')


  class Shape:

      def __init__(self, id):
          self.id = id

      def __str__(self):
          return 'Shape - ' + self.id


  default_shape = Shape('square')


  def _special_function():
      print('Special function')

  ```

  ## Importing modules

  > Whether we are importing our own local module, a third-party module or a
  > built-in module native to Python, the syntax is the same.

  - If the module is in the same directory as the file you wish to import it into,
    you can just directly import with:
    ```py
    import utils
    utils.specialFunction
    shape = utils.Shape('circle')
    ```
  - If the module you want to import is in a subdirectory, you will need to make
    that subdirectory a package in order to be able to import from it. This means
    adding an `__init__.py`. Then you can use the following import syntax:
    ```py
    from subdir import utils
    ...
    ```

  ### Different import syntax

  - If you don't want to have to prepend the imported module's name when using it
    (e.g. `utils.specialFunction`). You can import like so:

    ```py
    from utils import *
    specialFunction()
    ```

  - By default an import makes everything in the module available, however you can
    choose to import only a subset. E.g.:
    ```py
    from utils import Shape
    #  or with an alias:
    from utils import Shape as lorem
    ```

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

  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__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

  When used with a module, `__main__` indicates code that should be run straight
  away when the given script file is run. You won't always want to execute
  everything in the module file on execution so you can put this stuff outside of
  `__main__`

  Typically you will only want immediate execution to happen when **the module is
  the entrypoint** to the program.

  We indicate this with `__main__` as follows:

  ```py
  if __name__ == "__main__":
      print("This runs only if the module is the main module")
  ```

  ### Usage in packages

  The only real difference with packages is that you can also define a
  `__main__.py` file in the root of the package directory.

  This functions in the same manner as `__main__` in an individual module however
  this time it is not the entry point for a single script but the entrypoint of
  the package as a whole.

  > When the package is run directly as a script, the code in `__main__.py` is
  > executed, just like it would be if it were a standalone script. This allows a
  > package to be run as a script, as well as letting it contain modules that can
  > be imported separately.

  You can of course still have individual entrypoints for the modules that
  comprise the package.

  ### Running the package as a package

  If you want to run the whole package at once, rather than individually importing
  the modules that belong to it. You can run the following from the command-line:

  ```
  python -m package_name
  ```

  With this, Python will try to locate the `__main__.py` file and execute it as
  though it were a standalone script.

  ### Using a `main()` function

  To ensure that certain code runs on initialisation we can define a special
  `main` function or class method that runs when the module or package is
  loaded.We would put the main set-up logic in `main` and coordinate the execution
  of the module or package through it.

  ```py
  def main():
      printer(default_shape)
      shape = Shape("circle")
      printer(shape)

  if __name__ == "__main__":
      main()
  ```

  ### Example

  ```py
  '''palindrome module'''

  def is_palindrome(inp):
      inp_list = list(inp)
      inp_list_len = len(inp_list)
      for i in range(inp_list_len):
          if inp_list[i] != inp_list[inp_list_len - 1 - i]:
              return False
      return True


  def main():
      palindrome_one = "soros"
      palindrome_two = "torot"
      not_palindrome = "chair"

      print(is_palindrome(palindrome_one))
      print(is_palindrome(palindrome_two))
      print(is_palindrome(not_palindrome))


  if __name__ == '__main__':
      main()
  ```

raw_content:
  ---
  tags: [python, OOP]
  ---

  # Python modules

  ## Distinguishing _modules_ from _packages_

  Modules and packages in Python are very similar to modules in Node.js: a
  combination of several pieces of functionality (often written in a mix of
  different syntactic styles) bundled together to be used as a unit.

  - A **module** is basically just a script - a single Python file that you can
    import using the `import` statement
  - A **package** is a _collection of modules_

  A package is a whole directory which has an `__init__.py` at its root which
  designates it as a package (this can be empty, but it is necessary to have this
  file for the interpreter to understand that the directory is a package).

  ## Creating modules

  ### Naming modules

  The name of a module is the name of its file, e.g. `utils.py` defines the module
  `utils`. When we import a module we do not need to specify the extension.

  ### Example module

  Here is an example of a module.

  ```py
  """utils module"""

  print('Hello I am the utils module')


  def printer(some_object):
      print('printer')
      print(some_object)
      print('done')


  class Shape:

      def __init__(self, id):
          self.id = id

      def __str__(self):
          return 'Shape - ' + self.id


  default_shape = Shape('square')


  def _special_function():
      print('Special function')

  ```

  ## Importing modules

  > Whether we are importing our own local module, a third-party module or a
  > built-in module native to Python, the syntax is the same.

  - If the module is in the same directory as the file you wish to import it into,
    you can just directly import with:
    ```py
    import utils
    utils.specialFunction
    shape = utils.Shape('circle')
    ```
  - If the module you want to import is in a subdirectory, you will need to make
    that subdirectory a package in order to be able to import from it. This means
    adding an `__init__.py`. Then you can use the following import syntax:
    ```py
    from subdir import utils
    ...
    ```

  ### Different import syntax

  - If you don't want to have to prepend the imported module's name when using it
    (e.g. `utils.specialFunction`). You can import like so:

    ```py
    from utils import *
    specialFunction()
    ```

  - By default an import makes everything in the module available, however you can
    choose to import only a subset. E.g.:
    ```py
    from utils import Shape
    #  or with an alias:
    from utils import Shape as lorem
    ```

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

  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__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

  When used with a module, `__main__` indicates code that should be run straight
  away when the given script file is run. You won't always want to execute
  everything in the module file on execution so you can put this stuff outside of
  `__main__`

  Typically you will only want immediate execution to happen when **the module is
  the entrypoint** to the program.

  We indicate this with `__main__` as follows:

  ```py
  if __name__ == "__main__":
      print("This runs only if the module is the main module")
  ```

  ### Usage in packages

  The only real difference with packages is that you can also define a
  `__main__.py` file in the root of the package directory.

  This functions in the same manner as `__main__` in an individual module however
  this time it is not the entry point for a single script but the entrypoint of
  the package as a whole.

  > When the package is run directly as a script, the code in `__main__.py` is
  > executed, just like it would be if it were a standalone script. This allows a
  > package to be run as a script, as well as letting it contain modules that can
  > be imported separately.

  You can of course still have individual entrypoints for the modules that
  comprise the package.

  ### Running the package as a package

  If you want to run the whole package at once, rather than individually importing
  the modules that belong to it. You can run the following from the command-line:

  ```
  python -m package_name
  ```

  With this, Python will try to locate the `__main__.py` file and execute it as
  though it were a standalone script.

  ### Using a `main()` function

  To ensure that certain code runs on initialisation we can define a special
  `main` function or class method that runs when the module or package is
  loaded.We would put the main set-up logic in `main` and coordinate the execution
  of the module or package through it.

  ```py
  def main():
      printer(default_shape)
      shape = Shape("circle")
      printer(shape)

  if __name__ == "__main__":
      main()
  ```

  ### Example

  ```py
  '''palindrome module'''

  def is_palindrome(inp):
      inp_list = list(inp)
      inp_list_len = len(inp_list)
      for i in range(inp_list_len):
          if inp_list[i] != inp_list[inp_list_len - 1 - i]:
              return False
      return True


  def main():
      palindrome_one = "soros"
      palindrome_two = "torot"
      not_palindrome = "chair"

      print(is_palindrome(palindrome_one))
      print(is_palindrome(palindrome_two))
      print(is_palindrome(not_palindrome))


  if __name__ == '__main__':
      main()
  ```


path: zk/Python_package_management.md
sortable_path: zkPython_package_management.md
title: Package management
checksum: 8d33751ae6c257ae49886e5c708ebcc0595691303be95e90dc2af0e07d212900
created: 2024-03-30 09:03:20.686965827+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-types"]}
lead:
  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

body:
  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

  - The alternative is the native `pip` but you have to create virtual
    environments (`venv`) to manage packages at different versions.

  To make use of virtual environments in `pip` you have to create the virtual
  environment before installing anything:

  ```
  python3 -m venv venv
  ```

  This will create a `venv` directory in your project that will manage the
  handling of modules.

  > This is especially important in ArchLinux since without a virtual environment
  > it will ask you to install packages with `pacman` which is annoying for local
  > packages.

  You then activate the environment with:

  ```
  source venv3/bin/activate
  ```

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

  The `requirements.txt` file is similar to the `package.json` in Node projects.

  Each line of the `requirements.txt`` file specifies a package that your project
  depends on and, optionally, the desired version of that package. When you share
  your project with others or move it between different environments (e.g., from
  development to production), this file makes it easy to set up your environment
  with the right dependencies.

  ### Example

  ```
  Flask==1.1.2
  requests>=2.24.0
  numpy~=1.19.2
  pandas
  ```

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM

raw_content:
  ---
  tags: [python, data-types]
  ---

  # Package management

  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

  - The alternative is the native `pip` but you have to create virtual
    environments (`venv`) to manage packages at different versions.

  To make use of virtual environments in `pip` you have to create the virtual
  environment before installing anything:

  ```
  python3 -m venv venv
  ```

  This will create a `venv` directory in your project that will manage the
  handling of modules.

  > This is especially important in ArchLinux since without a virtual environment
  > it will ask you to install packages with `pacman` which is annoying for local
  > packages.

  You then activate the environment with:

  ```
  source venv3/bin/activate
  ```

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

  The `requirements.txt` file is similar to the `package.json` in Node projects.

  Each line of the `requirements.txt`` file specifies a package that your project
  depends on and, optionally, the desired version of that package. When you share
  your project with others or move it between different environments (e.g., from
  development to production), this file makes it easy to set up your environment
  with the right dependencies.

  ### Example

  ```
  Flask==1.1.2
  requests>=2.24.0
  numpy~=1.19.2
  pandas
  ```

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM


path: zk/Queue.md
sortable_path: zkQueue.md
title: Queues
lead: _Visualization of the queue data structure_
checksum: 07770787a6624e0fccf35e0a770a641009f179bfe320a3ef9237fe7dcdc9210f
created: 2024-03-30 09:03:20.712348837+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["data-structures"]}
body:
  _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.

raw_content:
  ---
  tags:
    - data-structures
  ---

  # 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.


path: zk/Quote_marks_in_Bash.md
sortable_path: zkQuote_marks_in_Bash.md
title: Quote marks in Bash
lead: ## Single-quotes (aka _strong_ quotes)
checksum: 9a8b2de955dcbf7f9a4a1cd5944dfd9aaf4e40a8d3eb764f5759eae1c1f39d51
created: 2024-03-30 09:03:20.717735752+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ## 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.

raw_content:
  ---
  tags:
    - shell
  ---

  # 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.


path: zk/RESTful_APIs.md
sortable_path: zkRESTful_APIs.md
title: RESTful APIs
lead: ## Definition of an API
checksum: facc11be40d1315db02b61b5b886a72db631eb09de9e4aa7aeeb283823c7b63a
created: 2024-03-30 09:03:20.722448378+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["APIs","REST"]}
body:
  ## Definition of an API

  An application programming interface (API) is a set of definitions and protocols
  for building and integrating application software. It can be thought of as a
  contract between an information provider and an informational consumer. The API
  is a mediator between the clients and the resources they wish to acquire from a
  server or database.

  ## REST

  REST stands for **Representational State Transfer**. It is a set of
  _architectural constraints_ on the structure of an API rather than a fixed
  protocol. It is a particular way of implementing client-server interaction over
  HTTP.

  When a request is made from a client to resources via RESTful API, the API
  transfers a representation of of the state of the resource to the requester or
  endpoint. The information is delivered via HTTP. The format can be of several
  types (HTML, XML, plaintext, Python, PHP etc) but is generally JSON because of
  its broad compatibility with multiple programming languages.

  ### Key constraints

  In order to qualify as RESTful, an API must meet the following constraints:

  1. **Uniform interface**: Possess a client-server architecture with request
     manage through HTTP
  1. **Client-server decoupling** : The client and server applications must be
     completely independent of one another. The _only_ information the client
     should know about the server is the URI it uses to request the resource, it
     can't interact with the server in any other way. Likewise, the server
     shouldn't modify the client application in any way (contrast for example SSR)
     other than passing the requested data via HTTP.
  1. **Statelessness** Server applications should not be able to store any data
     related to a client request. The request alone should contain all the
     information necessary for processing it, without recourse to any specifics of
     the client application. For example, a specification of POST with a certain
     JSON body and header authentication will be all that is provided to the
     server.
  1. **Cacheability** Where possible, resources should be cacheable on the client
     or server side. Server responses must contain information about whether
     caching is allowed for the delivered resource (you see this in the headers in
     the DevTools console). The goal here is to improve performance on the client
     side whilst increasing scaleability on the server side.
  1. **Layered system architecture** It may be the case that the data flow between
     the client and the server is not direct. For instance the request may be
     funneled through middleware or another program before it is received by the
     server. Similarly there may be several steps before the client receives the
     requested data. Whilst one should not assume a direct correspondence, REST
     APIs need to be designed so that neither the client nor the server can tell
     whether it communicates with the end application or an intermediary.

  ## Example

  A basic example of a REST API would be a series of methods corresponding to the
  main [HTTP request types](HTTP_request_types.md).

  | HTTP request type | URI                 | Action                      | Body ?                   |
  | ----------------- | ------------------- | --------------------------- | ------------------------ |
  | GET               | /api/customers      | Retrieve customers as array | No                       |
  | GET               | /api/customers/guid | Get a specific customer     | No, data comes from GUID |
  | PUT               | /api/customers/guid | Update an existing customer | Yes                      |
  | DELETE            | /api/customers/1    | Delete a customer           | No, data comes from GUID |
  | POST              | /api/customers      | Create a new customer       | Yes                      |

  // Add: PATCH and explain differenct from PUT

raw_content:
  ---
  tags: [APIs, REST]
  ---

  # RESTful APIs

  ## Definition of an API

  An application programming interface (API) is a set of definitions and protocols
  for building and integrating application software. It can be thought of as a
  contract between an information provider and an informational consumer. The API
  is a mediator between the clients and the resources they wish to acquire from a
  server or database.

  ## REST

  REST stands for **Representational State Transfer**. It is a set of
  _architectural constraints_ on the structure of an API rather than a fixed
  protocol. It is a particular way of implementing client-server interaction over
  HTTP.

  When a request is made from a client to resources via RESTful API, the API
  transfers a representation of of the state of the resource to the requester or
  endpoint. The information is delivered via HTTP. The format can be of several
  types (HTML, XML, plaintext, Python, PHP etc) but is generally JSON because of
  its broad compatibility with multiple programming languages.

  ### Key constraints

  In order to qualify as RESTful, an API must meet the following constraints:

  1. **Uniform interface**: Possess a client-server architecture with request
     manage through HTTP
  1. **Client-server decoupling** : The client and server applications must be
     completely independent of one another. The _only_ information the client
     should know about the server is the URI it uses to request the resource, it
     can't interact with the server in any other way. Likewise, the server
     shouldn't modify the client application in any way (contrast for example SSR)
     other than passing the requested data via HTTP.
  1. **Statelessness** Server applications should not be able to store any data
     related to a client request. The request alone should contain all the
     information necessary for processing it, without recourse to any specifics of
     the client application. For example, a specification of POST with a certain
     JSON body and header authentication will be all that is provided to the
     server.
  1. **Cacheability** Where possible, resources should be cacheable on the client
     or server side. Server responses must contain information about whether
     caching is allowed for the delivered resource (you see this in the headers in
     the DevTools console). The goal here is to improve performance on the client
     side whilst increasing scaleability on the server side.
  1. **Layered system architecture** It may be the case that the data flow between
     the client and the server is not direct. For instance the request may be
     funneled through middleware or another program before it is received by the
     server. Similarly there may be several steps before the client receives the
     requested data. Whilst one should not assume a direct correspondence, REST
     APIs need to be designed so that neither the client nor the server can tell
     whether it communicates with the end application or an intermediary.

  ## Example

  A basic example of a REST API would be a series of methods corresponding to the
  main [HTTP request types](HTTP_request_types.md).

  | HTTP request type | URI                 | Action                      | Body ?                   |
  | ----------------- | ------------------- | --------------------------- | ------------------------ |
  | GET               | /api/customers      | Retrieve customers as array | No                       |
  | GET               | /api/customers/guid | Get a specific customer     | No, data comes from GUID |
  | PUT               | /api/customers/guid | Update an existing customer | Yes                      |
  | DELETE            | /api/customers/1    | Delete a customer           | No, data comes from GUID |
  | POST              | /api/customers      | Create a new customer       | Yes                      |

  // Add: PATCH and explain differenct from PUT


path: zk/Read.md
sortable_path: zkRead.md
title: read
checksum: 4880d98c77c081d64c56a1cd89e8f03f7a42ee91b25a42725994ca2026a56f25
created: 2024-03-30 09:03:20.731255311+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
lead:
  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.

body:
  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.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.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
  ```

raw_content:
  ---
  tags:
    - shell
  ---

  # 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.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.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
  ```


path: zk/Rebasing.md
sortable_path: zkRebasing.md
title: Rebasing
checksum: be09e17373363834833d5deb64d2732b4c33199b79b14ab0e6dfd63676670f80
created: 2024-03-30 09:03:20.745468768+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  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.

body:
  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.

raw_content:
  ---
  tags:
    - git
  ---

  # 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.


path: zk/Reciprocals.md
sortable_path: zkReciprocals.md
title: Recipricols
checksum: ed560badcaa7ccb1a422db87818532d451e6e49d4b8d43d356089e8f9edf1af6
created: 2024-03-30 09:03:20.758504708+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","fractions","theorems"]}
lead:
  The [Property of Multiplicative Identity](Multiplicative%20identity.md) applies
  to fractions as well as to whole numbers:

body:
  The [Property of Multiplicative Identity](Multiplicative%20identity.md) applies
  to fractions as well as to whole numbers:

  $$
  \frac{a}{b} \cdot 1 = \frac{a}{b}
  $$

  With fractions there is a related property: the **Multiplicative Inverse**.

  > If $\frac{a}{b}$ is any fraction, the fraction $\frac{b}{a}$ is called the
  > _multiplicative inverse_ or _reciprocol_ of $\frac{a}{b}$. The product of a
  > fraction multiplied by its reciprocol will always be 1. $$ \frac{a}{b} \cdot
  > \frac{b}{a} = 1$$

  For example:

  $$
  \frac{3}{4} \cdot \frac{4}{3} = \frac{12}{12} = 1
  $$

  In this case $\frac{4}{3}$ is the reciprocol or multiplicative inverse of
  $\frac{3}{4}$.

  This accords with what we know a fraction to be: a representation of an amount
  that is less than one whole. When we multiply a fraction by its reciprocol, we
  demonstrate that it makes up one whole.

  This also means that whenever we have a whole number $n$, we can represent it
  fractionally by expressing it as $\frac{n}{1}$

raw_content:
  ---
  tags:
    - prealgebra
    - fractions
    - theorems
  ---

  # Recipricols

  The [Property of Multiplicative Identity](Multiplicative%20identity.md) applies
  to fractions as well as to whole numbers:

  $$
  \frac{a}{b} \cdot 1 = \frac{a}{b}
  $$

  With fractions there is a related property: the **Multiplicative Inverse**.

  > If $\frac{a}{b}$ is any fraction, the fraction $\frac{b}{a}$ is called the
  > _multiplicative inverse_ or _reciprocol_ of $\frac{a}{b}$. The product of a
  > fraction multiplied by its reciprocol will always be 1. $$ \frac{a}{b} \cdot
  > \frac{b}{a} = 1$$

  For example:

  $$
  \frac{3}{4} \cdot \frac{4}{3} = \frac{12}{12} = 1
  $$

  In this case $\frac{4}{3}$ is the reciprocol or multiplicative inverse of
  $\frac{3}{4}$.

  This accords with what we know a fraction to be: a representation of an amount
  that is less than one whole. When we multiply a fraction by its reciprocol, we
  demonstrate that it makes up one whole.

  This also means that whenever we have a whole number $n$, we can represent it
  fractionally by expressing it as $\frac{n}{1}$


path: zk/Recursion.md
sortable_path: zkRecursion.md
title: Schema
checksum: 4a8a39f5c37cf98784efe3d990418f7685f37a2348e7edcdb0b155b05a8e4b80
created: 2024-03-30 09:03:20.771235769+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["algorithms","data-structures","recursion"]}
lead:
  The general structure of a recursive function is as follows:
  ![javascript-recursion.png](javascript-recursion.png)

body:
  The general structure of a recursive function is as follows:
  ![javascript-recursion.png](javascript-recursion.png)

  ## Why use recursive functions?

  Recursion is made for solving problems that can be broken down into smaller,
  repetitive problems. It is especially good for working on things that have many
  possible branches but are too complex for an iterative approach or too costly in
  terms of memory and time complexity.

  Recursive programming differs from **iterative** programming but both have
  similar use cases. Looping is a canonical example of working iteratively.

  ## Base condition

  > Once a condition is met, the function stops calling itself. This is called a
  > base condition.

  Because recursion has the potential for infinity, to use it, we must specify a
  point at which it ends. However as we are not using an iterative approach we
  cannot rely on `while` or `foreach` to specify the boundaries of its operation.
  We call this the **base condition** and this will typically be specified using
  conditional logic.

  The schema for a recursive function with a base condition is:

  ```jsx
  function recurse() {
    if (condition) {
      recurse();
    } else {
      // stop calling recurse()
    }
  }

  recurse();
  ```

  ## Demonstrations

  ### Countdown

  ```jsx
  // program to count down numbers to 1
  function countDown(number) {
    // display the number
    console.log(number);

    // decrease the number value
    let newNumber = number - 1;

    // base case
    if (newNumber > 0) {
      countDown(newNumber);
    }
  }

  countDown(4);
  ```

  - This code takes `4` as it's input and then outputs a countdown returning:
    `4, 3, 2, 1`
  - In each iteration, the number value is decreased by 1
  - The base condition is `newNumber > 0` . This breaks the recursive loop once
    the output reaches `1` and stops it continuing into negative integers.

  Each stage in the process is noted below:

  ```
  countDown(4) prints 4 and calls countDown(3)
  countDown(3) prints 3 and calls countDown(2)
  countDown(2) prints 2 and calls countDown(1)
  countDown(1) prints 1 and calls countDown(0)
  ```

  ### Finding factorials

  > The factorial of a positive integer **n** is the product of all the positive
  > integers less than or equal to **n**.

  To arrive at the factorial of **n** you subtract 1 from **n** and multiply the
  result of the subtraction by **n**. You repeat until the subtractive process
  runs out of positive integers. For example, if 4 is **n,** the factorial of
  **n** is **24:**

  $$ 4 _ 3 _ 2 \*1 $$

  4 multiplied by 3 gives you 12, 12 multiplied by 2 gives you 24. 24 multiplied
  by 1 is 24.

  This is clearly a process that could be implemented with a recursive function:

  ```js
  // program to find the factorial of a number
  function factorial(x) {
    // if number is 0
    if (x === 0) {
      return 1;
    }

    // if number is positive
    else {
      return x * factorial(x - 1);
    }
  }

  let num = 3;

  // calling factorial() if num is non-negative
  if (num > 0) {
    let result = factorial(num);
    console.log(`The factorial of ${num} is ${result}`);
  }
  ```

  ![javascript-factorial 1.png](javascript-factorial%201.png)

raw_content:
  ---
  tags:
    - algorithms
    - data-structures
    - recursion
  ---

  > A recursive function is a function that calls itself in its definition.

  More generally recursion means when a thing is defined in terms of itself. There
  are visual analogues that help to represent the idea such as the Droste effect
  where an image contains a version of itself within itself. The ouroboros is
  another example. Also fractals display recursive properties.

  ## Schema

  The general structure of a recursive function is as follows:
  ![javascript-recursion.png](javascript-recursion.png)

  ## Why use recursive functions?

  Recursion is made for solving problems that can be broken down into smaller,
  repetitive problems. It is especially good for working on things that have many
  possible branches but are too complex for an iterative approach or too costly in
  terms of memory and time complexity.

  Recursive programming differs from **iterative** programming but both have
  similar use cases. Looping is a canonical example of working iteratively.

  ## Base condition

  > Once a condition is met, the function stops calling itself. This is called a
  > base condition.

  Because recursion has the potential for infinity, to use it, we must specify a
  point at which it ends. However as we are not using an iterative approach we
  cannot rely on `while` or `foreach` to specify the boundaries of its operation.
  We call this the **base condition** and this will typically be specified using
  conditional logic.

  The schema for a recursive function with a base condition is:

  ```jsx
  function recurse() {
    if (condition) {
      recurse();
    } else {
      // stop calling recurse()
    }
  }

  recurse();
  ```

  ## Demonstrations

  ### Countdown

  ```jsx
  // program to count down numbers to 1
  function countDown(number) {
    // display the number
    console.log(number);

    // decrease the number value
    let newNumber = number - 1;

    // base case
    if (newNumber > 0) {
      countDown(newNumber);
    }
  }

  countDown(4);
  ```

  - This code takes `4` as it's input and then outputs a countdown returning:
    `4, 3, 2, 1`
  - In each iteration, the number value is decreased by 1
  - The base condition is `newNumber > 0` . This breaks the recursive loop once
    the output reaches `1` and stops it continuing into negative integers.

  Each stage in the process is noted below:

  ```
  countDown(4) prints 4 and calls countDown(3)
  countDown(3) prints 3 and calls countDown(2)
  countDown(2) prints 2 and calls countDown(1)
  countDown(1) prints 1 and calls countDown(0)
  ```

  ### Finding factorials

  > The factorial of a positive integer **n** is the product of all the positive
  > integers less than or equal to **n**.

  To arrive at the factorial of **n** you subtract 1 from **n** and multiply the
  result of the subtraction by **n**. You repeat until the subtractive process
  runs out of positive integers. For example, if 4 is **n,** the factorial of
  **n** is **24:**

  $$ 4 _ 3 _ 2 \*1 $$

  4 multiplied by 3 gives you 12, 12 multiplied by 2 gives you 24. 24 multiplied
  by 1 is 24.

  This is clearly a process that could be implemented with a recursive function:

  ```js
  // program to find the factorial of a number
  function factorial(x) {
    // if number is 0
    if (x === 0) {
      return 1;
    }

    // if number is positive
    else {
      return x * factorial(x - 1);
    }
  }

  let num = 3;

  // calling factorial() if num is non-negative
  if (num > 0) {
    let result = factorial(num);
    console.log(`The factorial of ${num} is ${result}`);
  }
  ```

  ![javascript-factorial 1.png](javascript-factorial%201.png)


path: zk/Redirect_to_dev_null.md
sortable_path: zkRedirect_to_dev_null.md
title: Redirecting to /dev/null
lead: You'll see the following a lot when reading shell scripts:
checksum: 1864a7e2ce0dd078e01afeec825f780ffbceb38790e093fb936a971e522965c6
created: 2024-03-30 09:03:20.77646325+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  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.

raw_content:
  ---
  tags:
    - shell
  ---

  # 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.


path: zk/Redirection.md
sortable_path: zkRedirection.md
title: Redirection
lead: ## Redirecting outputs
checksum: e64c3fd247bb692dbe02ecb5f5d645298857b8d8675be4a8a9e3532475b2fc00
created: 2024-03-30 09:03:20.788996785+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ## Redirecting outputs

  The symbol `>` is called the **redirection operator** because it redirects
  `stdout` to another program or file. You most frequently use this when you want
  to save contents to a file rather than standard output.

  ```bash
  ls | grep d* > result.txt
  ```

  ### Combining redirection with file escriptors

  It is common practice to combine redirection with the
  [file descriptors](File_descriptors.md) to redirect
  the output of `stdout` and `stderr`. A common case is to
  [redirect error output to `/dev/null`](Redirect_to_dev_null.md).

  Redirection defaults to interpreting `>` as the redirection of `stdout` (`1`);

  ## Redirecting inputs

  We can also switch the direction of the redirection symbol and pass in a file to
  a command rather than command ouput to a file:

  ```bash
  sql-processing-program < data.sql
  ```

  We can redirect a string with three carets:

  ```bash
  program <<< "this is a string input"
  ```

  ## Appending

  We use `>>` to append contents on the next available line of a pre-existing
  file. Continuing on from the example above:

  ```bash
  echo 'These are the files I just grepped' >> result.txt
  ```

raw_content:
  ---
  tags:
    - shell
  ---

  # Redirection

  ## Redirecting outputs

  The symbol `>` is called the **redirection operator** because it redirects
  `stdout` to another program or file. You most frequently use this when you want
  to save contents to a file rather than standard output.

  ```bash
  ls | grep d* > result.txt
  ```

  ### Combining redirection with file escriptors

  It is common practice to combine redirection with the
  [file descriptors](File_descriptors.md) to redirect
  the output of `stdout` and `stderr`. A common case is to
  [redirect error output to `/dev/null`](Redirect_to_dev_null.md).

  Redirection defaults to interpreting `>` as the redirection of `stdout` (`1`);

  ## Redirecting inputs

  We can also switch the direction of the redirection symbol and pass in a file to
  a command rather than command ouput to a file:

  ```bash
  sql-processing-program < data.sql
  ```

  We can redirect a string with three carets:

  ```bash
  program <<< "this is a string input"
  ```

  ## Appending

  We use `>>` to append contents on the next available line of a pre-existing
  file. Continuing on from the example above:

  ```bash
  echo 'These are the files I just grepped' >> result.txt
  ```


path: zk/Reducing_fractions.md
sortable_path: zkReducing_fractions.md
title: Reducing fractions to their lowest terms
checksum: 703afbdd4fe816aed30ce456b551228944ce7cd82547bdac44fba35c544b2362
created: 2024-03-30 09:03:20.801961098+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","fractions"]}
lead:
  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

body:
  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

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

  Thus the fraction $\frac{2}{3}$ is reduced to its lowest terms because the
  greatest common divisor is 1. Neither the numerator or the denominator can be
  reduced to any lower terms. In contrast, the fraction $\frac{4}{6}$ is not
  reduced to its lowest terms because the greatest common divisor of both 4 and 6
  is 2, not 1.

  ### 1. Reducing with repeated application of divisors

  The following demonstrates the process of reducing a fraction to its lowest
  terms in a series of steps:

  $$
  \\frac{18}{24} = \frac{18/2}{24/2} = \frac{9}{12} = \frac{9/3}{12/3} = \frac{3}{4}
  $$

  \_Once we get to $\frac{3}{4}$ the greatest common divisor is 1, therefore
  $\frac{18}{24}$ has been reduced to its lowest terms \_.

  ### 2. Reducing in one step with the highest common divisor

  In the previous example the reduction took two steps: first we divided by two
  and then we divided by three. There is a more efficient way: find the
  [highest common divisor](Factors%20and%20divisors.md#greatest-common-divisor) of
  the numerator and denominator and then use this as the basis for the reduction.
  With this method, the reduction can be completed in a single step.

  The greatest common divisor of 18 and 24 is 6, thus:

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

  Note how our earlier two divisors 2 and 3 are
  [factors](Factors%20and%20divisors.md#factors) of 6, showing the consistency
  between the two methods.

  ### 3. Reducing with factors and cancellation

  The two methods above are not very systematic and are quite heuristic. The third
  approach is more systematic and relies on the
  [interchangeability of factors and divisors](Factors%20and%20divisors.md).

  Instead of thinking asking what is the greatest common divisor of 18 and 24 we
  could ask: which single number can we multiply by to get 18 and 24? Obviously
  both numbers are in the six times table. This is therefore to say that 6 is a
  [factor](Factors%20and%20divisors.md#factors) of both: we can multiply some
  number by 6 to arrive at both 18 and 24. The numbers are 3 and 4 respectively:

  $$
  \\begin{split}
  3 \cdot 6 = 18 \\
  4 \cdot 6  = 24
  \\end{split}
  $$

  Here, 3 and 4 are the multiplicands of the factor 6. As $\frac{3}{4}$ doesn't
  have a lower common factor, it is therefore defined in its lowest terms.

  Once we have reached this point, we no longer need the common factor 6, we can
  therefore cancel it out, leaving the multiplicands as the reduced fraction:

  $$
  \\begin{split}
  3  \cancel{\cdot6= 18}\\
  4  \cancel{\cdot6= 24}
  \\end{split}
  $$

  ### 4. Reducing with prime factorisation

  This is still a bit long-winded however particularly when finding the factors of
  larger numbers because we have to go through the factors of both numbers to find
  the largest held in common.

  A better method is to utilise [prime factorization](Prime%20factorization.md)
  combined with the canceling technique.

  First we find the prime factors of both the numerator and denominator:
  ![drawio-Page-7.drawio.png](drawio-Page-7.drawio.png)

  This gives us:

  $$
  \\frac{18}{24} = \frac{2 \cdot 3 \cdot 3}{2 \cdot 2 \cdot 2 \cdot 3}
  $$

  We then cancel out the factors held in common between the numerator and
  denominator:

  $$
  \\frac{\cancel{2} \cdot \cancel{3} \cdot 3}{\cancel{2} \cdot 2 \cdot 2 \cdot \cancel{3}}
  $$

  This gives us:

  $$
  \\frac{3}{2 \cdot 2}
  $$

  We then simplify the fraction as normal to its lowest term (conducting any
  multiplications required by what is left from the prime factorization):

  $$
  \\frac{3}{4}
  $$

  ## Reducing fractions that contain variables

  Superficially this looks to be more difficult but in fact we can apply the same
  prime factorization method to get the result.

  ### Demonstration

  _Reduce the following fraction to its lowest terms: $$\frac{25a^3b}{40a^2b^3}$$_

  The prime factors of the numerator and denominator:

  $$
  \\begin{split}
  25 = {5, 5} \\
  40 = {2,2,2,5}
  \\end{split}
  $$

  Now we apply canceling but we include the variable parts, treating them exactly
  the same as the coefficients. We break them out of their exponents however.

  $$\frac{25a^3b}{40a^2b^3} =\frac{5 \cdot 5 \cdot a \cdot a \cdot a \cdot b}{2 \cdot 2 \cdot 2 \cdot 5 \cdot a \cdot a \cdot b \cdot b \cdot b }$$

  Canceled:

  $$\frac{\cancel{5} \cdot 5 \cdot  \cancel{a} \cdot \cancel{a} \cdot a \cdot \cancel{b}}{2 \cdot 2 \cdot 2 \cdot \cancel{5} \cdot \cancel{a} \cdot \cancel{a} \cdot \cancel{b} \cdot b \cdot b }$$

  Which gives us:

  $$
  \\frac{5 \cdot a}{2 \cdot 2 \cdot 2 \cdot b \cdot b} = \frac{5a}{8b^2}
  $$

  ## Reducing fractions that contain negative values

  _Reduce the following fraction to its lowest terms: $$\frac{14y^5}{-35y^3}$$_

  - This fraction is an instance of a
    [fraction with unlike terms](Handling%20negative%20fractions.md#fractions-with-unlike-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

    ![draw.io-Page-8.drawio.png](draw.io-Page-8.drawio.png)

  - Cancel the coefficients and variable parts

    $$
    \\frac{14y^5}{-35y^3}=\frac{5 \cdot 7 \cdot 2 \cdot y \cdot y \cdot y \cdot y \cdot y}{-5 \cdot 7  \cdot y \cdot y \cdot y} = - \frac{2y^2}{5}
    $$

  _Reduce the following fraction to its lowest terms:
  $$\frac{- 12xy^2}{ - 18xy^2}$$_

  - This fraction is an instance of a
    [fraction with like terms](Handling%20negative%20fractions.md#fractions-with-like-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

  ![draw.io-Page-8.drawio 1.png](draw.io-Page-8.drawio%201.png)

  - Cancel the coefficients and variable parts

    $$

    * \\frac{12xy^2}{18xy^2}=\frac{3 \cdot 2 \cdot 2 \cdot x \cdot y \cdot y}{3 \cdot 7  \cdot 3 \cdot 2 \cdot x \cdot x \cdot y} = - \frac{2y}{3x}
    $$

raw_content:
  ---
  tags:
    - prealgebra
    - fractions
  ---

  ## Reducing fractions to their lowest terms

  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

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

  Thus the fraction $\frac{2}{3}$ is reduced to its lowest terms because the
  greatest common divisor is 1. Neither the numerator or the denominator can be
  reduced to any lower terms. In contrast, the fraction $\frac{4}{6}$ is not
  reduced to its lowest terms because the greatest common divisor of both 4 and 6
  is 2, not 1.

  ### 1. Reducing with repeated application of divisors

  The following demonstrates the process of reducing a fraction to its lowest
  terms in a series of steps:

  $$
  \\frac{18}{24} = \frac{18/2}{24/2} = \frac{9}{12} = \frac{9/3}{12/3} = \frac{3}{4}
  $$

  \_Once we get to $\frac{3}{4}$ the greatest common divisor is 1, therefore
  $\frac{18}{24}$ has been reduced to its lowest terms \_.

  ### 2. Reducing in one step with the highest common divisor

  In the previous example the reduction took two steps: first we divided by two
  and then we divided by three. There is a more efficient way: find the
  [highest common divisor](Factors%20and%20divisors.md#greatest-common-divisor) of
  the numerator and denominator and then use this as the basis for the reduction.
  With this method, the reduction can be completed in a single step.

  The greatest common divisor of 18 and 24 is 6, thus:

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

  Note how our earlier two divisors 2 and 3 are
  [factors](Factors%20and%20divisors.md#factors) of 6, showing the consistency
  between the two methods.

  ### 3. Reducing with factors and cancellation

  The two methods above are not very systematic and are quite heuristic. The third
  approach is more systematic and relies on the
  [interchangeability of factors and divisors](Factors%20and%20divisors.md).

  Instead of thinking asking what is the greatest common divisor of 18 and 24 we
  could ask: which single number can we multiply by to get 18 and 24? Obviously
  both numbers are in the six times table. This is therefore to say that 6 is a
  [factor](Factors%20and%20divisors.md#factors) of both: we can multiply some
  number by 6 to arrive at both 18 and 24. The numbers are 3 and 4 respectively:

  $$
  \\begin{split}
  3 \cdot 6 = 18 \\
  4 \cdot 6  = 24
  \\end{split}
  $$

  Here, 3 and 4 are the multiplicands of the factor 6. As $\frac{3}{4}$ doesn't
  have a lower common factor, it is therefore defined in its lowest terms.

  Once we have reached this point, we no longer need the common factor 6, we can
  therefore cancel it out, leaving the multiplicands as the reduced fraction:

  $$
  \\begin{split}
  3  \cancel{\cdot6= 18}\\
  4  \cancel{\cdot6= 24}
  \\end{split}
  $$

  ### 4. Reducing with prime factorisation

  This is still a bit long-winded however particularly when finding the factors of
  larger numbers because we have to go through the factors of both numbers to find
  the largest held in common.

  A better method is to utilise [prime factorization](Prime%20factorization.md)
  combined with the canceling technique.

  First we find the prime factors of both the numerator and denominator:
  ![drawio-Page-7.drawio.png](drawio-Page-7.drawio.png)

  This gives us:

  $$
  \\frac{18}{24} = \frac{2 \cdot 3 \cdot 3}{2 \cdot 2 \cdot 2 \cdot 3}
  $$

  We then cancel out the factors held in common between the numerator and
  denominator:

  $$
  \\frac{\cancel{2} \cdot \cancel{3} \cdot 3}{\cancel{2} \cdot 2 \cdot 2 \cdot \cancel{3}}
  $$

  This gives us:

  $$
  \\frac{3}{2 \cdot 2}
  $$

  We then simplify the fraction as normal to its lowest term (conducting any
  multiplications required by what is left from the prime factorization):

  $$
  \\frac{3}{4}
  $$

  ## Reducing fractions that contain variables

  Superficially this looks to be more difficult but in fact we can apply the same
  prime factorization method to get the result.

  ### Demonstration

  _Reduce the following fraction to its lowest terms: $$\frac{25a^3b}{40a^2b^3}$$_

  The prime factors of the numerator and denominator:

  $$
  \\begin{split}
  25 = {5, 5} \\
  40 = {2,2,2,5}
  \\end{split}
  $$

  Now we apply canceling but we include the variable parts, treating them exactly
  the same as the coefficients. We break them out of their exponents however.

  $$\frac{25a^3b}{40a^2b^3} =\frac{5 \cdot 5 \cdot a \cdot a \cdot a \cdot b}{2 \cdot 2 \cdot 2 \cdot 5 \cdot a \cdot a \cdot b \cdot b \cdot b }$$

  Canceled:

  $$\frac{\cancel{5} \cdot 5 \cdot  \cancel{a} \cdot \cancel{a} \cdot a \cdot \cancel{b}}{2 \cdot 2 \cdot 2 \cdot \cancel{5} \cdot \cancel{a} \cdot \cancel{a} \cdot \cancel{b} \cdot b \cdot b }$$

  Which gives us:

  $$
  \\frac{5 \cdot a}{2 \cdot 2 \cdot 2 \cdot b \cdot b} = \frac{5a}{8b^2}
  $$

  ## Reducing fractions that contain negative values

  _Reduce the following fraction to its lowest terms: $$\frac{14y^5}{-35y^3}$$_

  - This fraction is an instance of a
    [fraction with unlike terms](Handling%20negative%20fractions.md#fractions-with-unlike-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

    ![draw.io-Page-8.drawio.png](draw.io-Page-8.drawio.png)

  - Cancel the coefficients and variable parts

    $$
    \\frac{14y^5}{-35y^3}=\frac{5 \cdot 7 \cdot 2 \cdot y \cdot y \cdot y \cdot y \cdot y}{-5 \cdot 7  \cdot y \cdot y \cdot y} = - \frac{2y^2}{5}
    $$

  _Reduce the following fraction to its lowest terms:
  $$\frac{- 12xy^2}{ - 18xy^2}$$_

  - This fraction is an instance of a
    [fraction with like terms](Handling%20negative%20fractions.md#fractions-with-like-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

  ![draw.io-Page-8.drawio 1.png](draw.io-Page-8.drawio%201.png)

  - Cancel the coefficients and variable parts

    $$

    * \\frac{12xy^2}{18xy^2}=\frac{3 \cdot 2 \cdot 2 \cdot x \cdot y \cdot y}{3 \cdot 7  \cdot 3 \cdot 2 \cdot x \cdot x \cdot y} = - \frac{2y}{3x}
    $$


path: zk/Regular_expressions_in_SQL.md
sortable_path: zkRegular_expressions_in_SQL.md
title: Regular expressions in SQL
lead:
  ```sql
  SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

checksum: 469db48f16db9b164763ed11a358fbaae7d72cb583f93941b711411ba3907f51
created: 2024-03-30 09:03:20.887464229+00:00
modified: 2024-06-15 09:48:06.097153958+00:00
metadata: {"tags":["SQL","regex","databases"]}
body:
  ```sql
  SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

  Guyana
  Mexico
  Myanmar
  ```

raw_content:
  ---
  tags:
    - SQL
    - regex
    - databases
  ---

  # Regular expressions in SQL

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

  Guyana
  Mexico
  Myanmar
  ```


path: zk/Reiteration.md
sortable_path: zkReiteration.md
title: Reiteration
checksum: ea9b8e71786e265aab7d0a50515cb159b3afc4a3ccb47c2e939ccedb9d2915d7
created: 2024-03-30 09:03:20.890874329+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":[]}
lead:
  **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.

body:
  **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)

raw_content:
  ---
  tags: []
  ---

  # 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)


path: zk/Relation_between_kernel_and_CPU.md
sortable_path: zkRelation_between_kernel_and_CPU.md
title: Relation between the kernel and CPU
checksum: 932e2ae629c9d9a25ed03d37a9f10bd952212ef231f4b486ea1f9940a7e1b44c
created: 2024-03-30 09:03:20.896906687+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["kernel","CPU"]}
lead:
  It can be confusing to understand how the kernel and CPU interact with one
  another. Whilst it is true to say the kernel mediates between the hardware and
  user processes, this led me to think that the kernel was somehow 'over and
  above' the actions of the CPU. This is wrong and if you think about it, how
  could this be since any process, kernel included, requires the processor? The
  kernel is executed by and loaded into the CPU just like any other instruction in
  the
  [fetch, decode, execute cycle](Fetch_decode_execute.md)
  of the CPU.

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

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

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

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

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

raw_content:
  ---
  tags:
    - kernel
    - CPU
  ---

  # Relation between the kernel and CPU

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

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

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

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

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


path: zk/Relational_database_architecture.md
sortable_path: zkRelational_database_architecture.md
title: Relational database architecture
lead: Tables, fields and records are the basic building blocks of databases
checksum: 314fcee16a259d511b08a47358c1ba6fec365469a928cbf5e48bf71d291fe5d0
created: 2024-03-30 09:03:20.905418741+00:00
modified: 2024-06-15 09:46:21.898386581+00:00
metadata: {"tags":[]}
body:
  Tables, fields and records are the basic building blocks of databases

  ![](/img/FL-Databases-1.5_terminology.gif)

  ## Table

  A group of similar data with rows for **records** and columns for each
  **field**.

  ## Record

  A horizontal row: a collection of items which may be of different data types all
  relating to the individual or object that the record describes. A single _entry_
  in the table. Sometimes called **row** interchangeably.

  ## Field

  A vertical column: stores a single particular unit of data for each record. Each
  field must use the same data type. Sometimes called **field** interchangeably.

  Each individual field has **properties:** such as the data type, length or the
  total memory allocation.

raw_content:
  ---
  tags: []
  ---

  # Relational database architecture

  Tables, fields and records are the basic building blocks of databases

  ![](/img/FL-Databases-1.5_terminology.gif)

  ## Table

  A group of similar data with rows for **records** and columns for each
  **field**.

  ## Record

  A horizontal row: a collection of items which may be of different data types all
  relating to the individual or object that the record describes. A single _entry_
  in the table. Sometimes called **row** interchangeably.

  ## Field

  A vertical column: stores a single particular unit of data for each record. Each
  field must use the same data type. Sometimes called **field** interchangeably.

  Each individual field has **properties:** such as the data type, length or the
  total memory allocation.


path: zk/Remote_tracking_branches.md
sortable_path: zkRemote_tracking_branches.md
title: Remote tracking branches
checksum: 775d9cfcc8eb49533dfa647d6fc6911b93fc101e8c2d79da117d0865f0bb5f3b
created: 2024-03-30 09:03:20.909141849+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  A remote tracking branch is a **local** snapshot or reference to the state of a
  branch on a remote repository.

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

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

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

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

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

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

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

raw_content:
  ---
  tags: [git]
  ---

  # Remote tracking branches

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

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

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

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

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

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

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


path: zk/Rename_a_branch.md
sortable_path: zkRename_a_branch.md
title: Rename a branch
lead: ### In local development
checksum: e8c060552e8fa8aad44a72102793c1db506b6091b9f8a57b3b216a90c49c8030
created: 2024-03-30 09:03:20.913303933+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git","procedural"]}
body:
  ### In local development

  ```bash
  git branch -m <old_name> <new_name>
  ```

  ### Update the remote

  ```bash
  git push origin -u <new_name>
  ```

raw_content:
  ---
  tags: [git, procedural]
  ---

  # Rename a branch

  ### In local development

  ```bash
  git branch -m <old_name> <new_name>
  ```

  ### Update the remote

  ```bash
  git push origin -u <new_name>
  ```


path: zk/Reset_to_remote_version.md
sortable_path: zkReset_to_remote_version.md
title: Reset to remote version of a branch
checksum: 4275e3738538e2f4224803c94c28cbb651c5bde268c007b9541dd886624806d9
created: 2024-03-30 09:03:20.918172854+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git","procedural"]}
lead:
  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`.

body:
  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
  ```

raw_content:
  ---
  tags: [git, procedural]
  ---

  # 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
  ```


path: zk/Resistance.md
sortable_path: zkResistance.md
title: Resistance
lead: - Resistance is opposition to the flow of [current](./Current.md).
checksum: 7531375cbeecf1f1985d5dfaa5d6f7501bc12fa20ec74096a7b8a65343f11009
created: 2024-03-30 09:03:20.922231712+00:00
modified: 2024-05-12 10:55:05.812886227+00:00
metadata: {"tags":["physics","electricity"]}
body:
  - Resistance is opposition to the flow of [current](./Current.md).

  - Different materials have different levels of resistance. For example glass and
    rubber are excellent resistors whereas silver and copper offer little
    resistance to current flow.

  - We utilise **resistors** to control the flow of current in a circuit.

  ## Relationship between _resistance_ and _insulation_

  Resistance and insulation are not the same thing although they relate to the
  same natural phenomena.

  Resistance is a property of an electrical circuit whereas insularity is a
  property of substances found in the world.

  Similarly, insulators are naturally occuring materials that resist the flow of
  current to different degrees whereas a resistor is a man-made electrical
  component that is used to _control_ the flow of current in a circuit.

  ## Factors affecting resistance

  - The larger the diameter of an electric wire, the lower the electrical
    resistance to the current flow. (If we use the analogy of electricity as
    water-flow: the wider the pipe, the more water that can flow.)
  - As a conductor heats up (e.g. copper, aluminium wire), its overall resistance
    increases.

  ## Notation and scientific expression

  ### Resistance

  - We use $R$ to represent resistance
  - The unit of resistance is **ohms** ($\Omega$)

  > One ohm is the resistance of a circuit or circuit element that permits a
  > steady current flow of one [amp](Current.md#formal-expression) (one
  > coulomb/second) when one [volt](Voltage.md#voltage) is applied to the circuit.

  ### Conductance

  - We use $G$ to represent conductance
  - The unit of conductance is **Mho** (ohm spelled backwards) ($\mho$)

  > Conductance is the ability of a material to pass electrons

  > Given that resistance is the opposite of conductance, the relation between the
  > two quantities can be expressed via a recipricol: $R = 1/G$ and $G = 1/R$

  ## Ohm's Law

  The relationship between current, resistance and voltage is expressed in
  [Ohm's Law](Ohms_Law.md).

  ## Resistors

  A resistor is an electrical component that can be used in circuits to introduce
  specific amounts to resistance where needed. This is typically done in order to
  temper the total voltage and so keep the current flowing within certain set
  parameters.

raw_content:
  ---
  tags: [physics, electricity]
  ---

  # Resistance

  - Resistance is opposition to the flow of [current](./Current.md).

  - Different materials have different levels of resistance. For example glass and
    rubber are excellent resistors whereas silver and copper offer little
    resistance to current flow.

  - We utilise **resistors** to control the flow of current in a circuit.

  ## Relationship between _resistance_ and _insulation_

  Resistance and insulation are not the same thing although they relate to the
  same natural phenomena.

  Resistance is a property of an electrical circuit whereas insularity is a
  property of substances found in the world.

  Similarly, insulators are naturally occuring materials that resist the flow of
  current to different degrees whereas a resistor is a man-made electrical
  component that is used to _control_ the flow of current in a circuit.

  ## Factors affecting resistance

  - The larger the diameter of an electric wire, the lower the electrical
    resistance to the current flow. (If we use the analogy of electricity as
    water-flow: the wider the pipe, the more water that can flow.)
  - As a conductor heats up (e.g. copper, aluminium wire), its overall resistance
    increases.

  ## Notation and scientific expression

  ### Resistance

  - We use $R$ to represent resistance
  - The unit of resistance is **ohms** ($\Omega$)

  > One ohm is the resistance of a circuit or circuit element that permits a
  > steady current flow of one [amp](Current.md#formal-expression) (one
  > coulomb/second) when one [volt](Voltage.md#voltage) is applied to the circuit.

  ### Conductance

  - We use $G$ to represent conductance
  - The unit of conductance is **Mho** (ohm spelled backwards) ($\mho$)

  > Conductance is the ability of a material to pass electrons

  > Given that resistance is the opposite of conductance, the relation between the
  > two quantities can be expressed via a recipricol: $R = 1/G$ and $G = 1/R$

  ## Ohm's Law

  The relationship between current, resistance and voltage is expressed in
  [Ohm's Law](Ohms_Law.md).

  ## Resistors

  A resistor is an electrical component that can be used in circuits to introduce
  specific amounts to resistance where needed. This is typically done in order to
  temper the total voltage and so keep the current flowing within certain set
  parameters.


path: zk/Restructure_URLs.md
sortable_path: zkRestructure_URLs.md
title: AWS Lambda examples
lead: ## Reconstruct CloudFront URLs
checksum: 6a911ce9d3aa21da4b42240dc00369ab6f54b0e35dca6f1cd3d11e804463b857
created: 2024-03-30 09:03:20.938924551+00:00
modified: 2024-06-15 09:50:42.956894178+00:00
metadata: {"tags":["AWS","aws-lambda"]}
body:
  ## Reconstruct CloudFront URLs

  ```js
  exports.handler = (event, context, callback) => {
    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, "/index.html");

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);
  };
  ```

  Let's walk through the above example making reference to the general structure
  of the
  [AWS Lambda handler function](Lambda_handler_function.md):

  1. The `event` parameter is invoked to gain access to the event that triggered
     the function. This is a CloudFront request event which is targetted with
     `event.Records[0].cf.request`
  2. We classify this request as the `olduri` since it doesn't have the form we
     want.
  3. We mutate the original request by replacing `/` with `/index.html`
  4. We then re-assign the `request.uri` value to the value of the new URI.
  5. Finally we invoke the `callback` parameter to signal the completion of the
     transformation and return the new request as the return value.

raw_content:
  ---
  tags:
    - AWS
    - aws-lambda
  ---

  # AWS Lambda examples

  ## Reconstruct CloudFront URLs

  ```js
  exports.handler = (event, context, callback) => {
    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, "/index.html");

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);
  };
  ```

  Let's walk through the above example making reference to the general structure
  of the
  [AWS Lambda handler function](Lambda_handler_function.md):

  1. The `event` parameter is invoked to gain access to the event that triggered
     the function. This is a CloudFront request event which is targetted with
     `event.Records[0].cf.request`
  2. We classify this request as the `olduri` since it doesn't have the form we
     want.
  3. We mutate the original request by replacing `/` with `/index.html`
  4. We then re-assign the `request.uri` value to the value of the new URI.
  5. Finally we invoke the `callback` parameter to signal the completion of the
     transformation and return the new request as the return value.


path: zk/Retrieve_data_from_SQL_table.md
sortable_path: zkRetrieve_data_from_SQL_table.md
title: Retrieve data from table with SQL SELECT statement
checksum: bd9cfcf86d3db4b0d93097db4940a0538df1f7ee46e5928de789034637659e8b
created: 2024-03-30 09:03:20.947544099+00:00
modified: 2024-06-15 09:48:11.177255052+00:00
metadata: {"tags":["SQL","databases"]}
lead:
  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

body:
  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

  _A table named `models`:_

  | modelId | name                 | cores | releaseDate |
  | ------- | -------------------- | ----- | ----------- |
  | 2       | Raspberry Pi Model B | 2     | 2022-11-19  |
  | 3       | Raspberry Pi Model C | 4     | 2022-11-25  |
  | 4       | MacBook Pro M2       | 9     | 2022-03-18  |

  ## Basic usage

  ```sql
  SELECT name FROM models
  ```

  We can pass in a comma-separated **list of fields**:

  ```sql
  SELECT name, releaseDate FROM models
  ```

  ## With parameters

  ### `WHERE`

  The `WHERE` clause specifies a search criterion. The `WHERE` clause should
  always be last in the syntax. The clauses are always written in this order:
  `FROM` followed by `WHERE`

  ```sql
  SELECT name FROM models WHERE cores > 3
  ```

  ### Compound statements

  Compound statements allow you to apply more filters to your clauses within an
  SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by
  using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` ,
  `<=` ...)

  Multiple clauses:

  ```sql
  SELECT name, ram, release_date
  FROM model
  WHERE release_date > '2018-01-01' AND ram > 512;
  ```

  More complex logic achieve with parentheses:

  ```sql
  SELECT name, cores, release_date
  FROM model
  WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
  ```

  ## Transform returned data

  We can apply **ordering** to the return data

  ```sql
  SELECT name FROM models ORDER BY name, cores
  SELECT name FROM models ORDER BY name, cores DESC
  ```

  > `ORDER BY` always comes last, after the selection and any filtering clauses
  > but _before_ a `WHERE` clause

  ## Paginate

  We can break our returned data into blocks with `LIMIT`

  ```sql
  LIMIT 5 -- Return first five items
  LIMIT 5,5 -- Return first five items from the sixth row
  ```

raw_content:
  ---
  tags:
    - SQL
    - databases
  ---

  # Retrieve data from table with SQL `SELECT` statement

  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

  _A table named `models`:_

  | modelId | name                 | cores | releaseDate |
  | ------- | -------------------- | ----- | ----------- |
  | 2       | Raspberry Pi Model B | 2     | 2022-11-19  |
  | 3       | Raspberry Pi Model C | 4     | 2022-11-25  |
  | 4       | MacBook Pro M2       | 9     | 2022-03-18  |

  ## Basic usage

  ```sql
  SELECT name FROM models
  ```

  We can pass in a comma-separated **list of fields**:

  ```sql
  SELECT name, releaseDate FROM models
  ```

  ## With parameters

  ### `WHERE`

  The `WHERE` clause specifies a search criterion. The `WHERE` clause should
  always be last in the syntax. The clauses are always written in this order:
  `FROM` followed by `WHERE`

  ```sql
  SELECT name FROM models WHERE cores > 3
  ```

  ### Compound statements

  Compound statements allow you to apply more filters to your clauses within an
  SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by
  using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` ,
  `<=` ...)

  Multiple clauses:

  ```sql
  SELECT name, ram, release_date
  FROM model
  WHERE release_date > '2018-01-01' AND ram > 512;
  ```

  More complex logic achieve with parentheses:

  ```sql
  SELECT name, cores, release_date
  FROM model
  WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
  ```

  ## Transform returned data

  We can apply **ordering** to the return data

  ```sql
  SELECT name FROM models ORDER BY name, cores
  SELECT name FROM models ORDER BY name, cores DESC
  ```

  > `ORDER BY` always comes last, after the selection and any filtering clauses
  > but _before_ a `WHERE` clause

  ## Paginate

  We can break our returned data into blocks with `LIMIT`

  ```sql
  LIMIT 5 -- Return first five items
  LIMIT 5,5 -- Return first five items from the sixth row
  ```


path: zk/Role_of_unique_key_in_relational_databases.md
sortable_path: zkRole_of_unique_key_in_relational_databases.md
title: Unique key
checksum: 7878d926038dcbc9f1511610d308b67f1133686457a748fc98cf72c4d659466f
created: 2024-03-30 09:03:20.95077825+00:00
modified: 2024-06-15 09:47:04.459251164+00:00
metadata: {"tags":["databases"]}
lead:
  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

body:
  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

  This is essential for carrying out operations across database tables and for
  creating and deleting database entires in accordance with the
  [ACID principle](ACID_principle.md). It is also a safeguard: it means
  you can always identify a record by itself and don't have to rely on generic
  queries to identify it.

  Sometimes you will have a dedicated field such as `UNIQUE_ID` for the unique
  key. Other times you can use an existing field to fulfil that function. When an
  existing, visible column is used as the unique key it is called the **primary
  key**. Other times the unique key can be hidden from the table.

  In both cases the following constraints **must be met:**

  1. No two records can have the **same** primary key data
  1. The primary key value should **never be reused**. Thus, if a record is
     deleted from the table, it should not be re-allocated to a new record.
  1. A primary key value **must not be modified** once it has been created
  1. A primary key **must have a value**; it cannot be `null`

raw_content:
  ---
  tags:
    - databases
  ---

  # Unique key

  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

  This is essential for carrying out operations across database tables and for
  creating and deleting database entires in accordance with the
  [ACID principle](ACID_principle.md). It is also a safeguard: it means
  you can always identify a record by itself and don't have to rely on generic
  queries to identify it.

  Sometimes you will have a dedicated field such as `UNIQUE_ID` for the unique
  key. Other times you can use an existing field to fulfil that function. When an
  existing, visible column is used as the unique key it is called the **primary
  key**. Other times the unique key can be hidden from the table.

  In both cases the following constraints **must be met:**

  1. No two records can have the **same** primary key data
  1. The primary key value should **never be reused**. Thus, if a record is
     deleted from the table, it should not be re-allocated to a new record.
  1. A primary key value **must not be modified** once it has been created
  1. A primary key **must have a value**; it cannot be `null`


path: zk/Routing_on_link_click.md
sortable_path: zkRouting_on_link_click.md
title: Test: Routing on link click
lead: ## Component
checksum: 0935aa4e5e1e4051e4ca684aa0735d3b0fb3a555a93412746712f20724dee40b
created: 2024-03-30 09:03:20.966472926+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","react","testing"]}
body:
  ## Component

  ```jsx
  const CertificateHtmlLink = () => {
    return (
      <div className="certificate-html-link html-version-message">
        <Link className="btn btn-primary ml-2" to="/some-location">
          View HTML version
        </Link>
      </div>
    );
  };
  ```

  ## Test

  ```js
  import { render, fireEvent } from "@testing-library/react";
  import { Router } from "react-router-dom";

  describe("<CertificateHtmlLink", () => {
    it("should link to dynamic HTML certificate page URL on click event", () => {
      // Arrange:
      const history = createMemoryHistory({ initialEntries: ["/"] });

      // Act:
      const { getByText } = render(
        <Router history={history}>
          <CertificateHtmlLink to="/certificate/123" />
        </Router>
      );

      // Assert:
      expect(history.location.pathname).toBe("/");
      fireEvent.click(getByText("View HTML version"));
      expect(history.location.pathname).toBe("/certificate/123");
    });
  });
  ```

raw_content:
  ---
  tags:
    - javascript
    - react
    - testing
  ---

  # Test: Routing on link click

  ## Component

  ```jsx
  const CertificateHtmlLink = () => {
    return (
      <div className="certificate-html-link html-version-message">
        <Link className="btn btn-primary ml-2" to="/some-location">
          View HTML version
        </Link>
      </div>
    );
  };
  ```

  ## Test

  ```js
  import { render, fireEvent } from "@testing-library/react";
  import { Router } from "react-router-dom";

  describe("<CertificateHtmlLink", () => {
    it("should link to dynamic HTML certificate page URL on click event", () => {
      // Arrange:
      const history = createMemoryHistory({ initialEntries: ["/"] });

      // Act:
      const { getByText } = render(
        <Router history={history}>
          <CertificateHtmlLink to="/certificate/123" />
        </Router>
      );

      // Assert:
      expect(history.location.pathname).toBe("/");
      fireEvent.click(getByText("View HTML version"));
      expect(history.location.pathname).toBe("/certificate/123");
    });
  });
  ```


path: zk/Rules_for_operations_on_like_and_unlike_terms.md
sortable_path: zkRules_for_operations_on_like_and_unlike_terms.md
title: Addition
lead: ### Like terms
checksum: b14e083fb61dec1ce1b85a9981265684b782ee062018ec7292d83734b7bd23c5
created: 2024-03-30 09:03:20.970920754+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra"]}
body:
  ### 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
  $$

raw_content:
  ---
  tags:
    - prealgebra
  ---

  ## 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
  $$


path: zk/S3.md
sortable_path: zkS3.md
title: S3
checksum: 71de289fb1009995825d1050865f4e550269258bd276f23ef7e28099c78b7165
created: 2024-03-30 09:03:20.973978897+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS"]}
lead:
  You can think of S3 as an external mounted harddrive for storing raw binary data
  (images, soundfiles, documents etc).

body:
  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.

raw_content:
  ---
  tags: [AWS]
  ---

  # 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.


path: zk/SAM.md
sortable_path: zkSAM.md
title: AWS SAM
checksum: f8c24e34ef80334d12ece3ae1f8ab00756aa1fade97ebc1202b2e78096913b62
created: 2024-03-30 09:03:20.980092239+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS"]}
lead:
  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

body:
  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

  The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
  SAM syntax gets transformed into CloudFormation during the deployment process.
  (CloudFormation is a broader and more robust AWS tool for large, highly
  scaleable infrastructures).

  ## Key features of SAM

  - Single deployment configuration
  - Integration with development tools
  - Local testing and debugging
  - Built on AWS CloudFormation

  ## Main technologies required

  ### Docker

  Whilst SAM can be used to create a deployable file for AWS it can also be run as
  a container for local development with Docker.

  ### AWS CLI

  This is installed using Python and allows you to interact directly with AWS via
  the command-line.

  ### AWS SAM CLI

  See
  [https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)

  ## Setting up credentials for the AWS CLI

  You require an access key for the given
  [IAM user](zk/AWS_User_management_and_roles.md#iam). You should create an IAM
  account specific to the project with bounded permissions.

  ```
  aws configure
  AWS Access Key ID [None]: AK*******
  AWS Secret Access Key [None]: ukp******
  Default region name [None]:
  Default output format [None]:
  ```

  This information can be found in the Security Credentials section of the given
  [IAM](zk/AWS_User_management_and_roles.md#iam) user:

  ![](/img/access-key-aws.png)

  ### Switching between credentials

  You should set up a different IAM user for each project.

  You can do this with:

  ```sh
  aws configure --profile <profile-name>
  ```

  This will then ask you to add the credentials for the user.

  You can switch between different credentials for the user as follows:

  ```sh
  AWS_PROFILE=<profile-name> sam build

  ```

  ## Starting a SAM project

  First create a directory for your project which will serve as the repository:

  ```sh
  mkdir aws-sam-learning
  cd aws-sam-learning
  ```

  Then we can use the `sam` cli to bootstrap the project:

  ```sh
  sam init --runtime nodejs16.x
  ```

  We can just click through and accept the basic HelloWorld Lambda.

  This will create the Lambda as well as an API Gateway trigger URL.

  ### `template.yaml`

  This is autogenerated and details the main constituents of the project. There
  are lots of fields but the most important are the following:

  ```yaml
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
  ```

  This details the location of the [handler function](/Lambda_handler_function.md)
  which is contained at the path `hello-world/app.js`:

  ```js
  exports.lambdaHandler = async (event, context) => {
    try {
      // const ret = await axios(url);
      response = {
        statusCode: 200,
        body: JSON.stringify({
          message: "hello world",
          // location: ret.data.trim()
        }),
      };
    } catch (err) {
      console.log(err);
      return err;
    }

    return response;
  };
  ```

  It also lists the `get` event that we can use to call API Gateway and trigger
  the Lambda.

  The full template is below:

  ![](/img/sam-template-yaml.png)

  ## Adding our own code

  We will create our own function and API Gateway trigger.

  We will place our function after the existing `HelloWorldFunction`

  ```yaml
  ClockFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: clock/
      Handler: handler.clock
      Runtime: nodejs16.x
    Events:
      ClockApi:
        Type: Api
        Properties:
          Path: /clock
          Method: get
  ```

  We can test the syntax with:

  ```sh
  sam validate
  ```

  Just like with `HelloWorld`, we will create a directory for this function:
  `clock` and we will initialise it as an `npm` project.

  ```sh
  mkdir clock
  cd clock
  npm init
  ```

  We will use `handler.js` as our root, handler function.

  We have said in the template file that our `Handler: handler.clock`, therefore
  the main function in the `handler` module should be `clock`:

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

  exports.clock = async (event) => {
    console.log("Clock function run");
    const message = moment().format();
    const response = {
      statusCode: 200,
      body: JSON.stringify(message),
    };
    return response;
  };
  ```

  The directory structure is as follows:

  ![](/_img/sam-directory.png)

  When we call the API Gateway path `/clock` with `GET`, our function will be
  triggered.

  ## Deploying the project

  We will now deploy our project to AWS from the local environment.

  The process is as follows:

  1. Build
  2. Package
  3. Deploy

  ### Build

  We need to install the runtime dependencies for the function. We do this by
  running `sam build`. This ignores test files and development dependencies and
  installs the project dependencies and source files to a temporary subdirectory.

  ![](/img/sam-build.png)

  The build directory is `.aws-sam/build/`. There will be a subdirectory for each
  of our files.

  ### Package

  As noted, CloudFront handles the deployment of the application. It can only
  receive one file as an input. The packaging process consists in creating that
  single file.

  The packaging proces will first archive all of the project artefacts into a zip
  file and then upload that to [S3](zk/AWS_S3.md). A reference to this S3 entity
  is then provided to CloudFormation.

  ![](/img/s3-package-again.svg)

  The command is as follows:

  ```sh
  sam package
    --template-file template.yaml
    --output-template-file pkg.yml
    --region eu-west-1
  ```

  This will automatically create a hashed bucket name for you in S3 (I have tried
  to add my own naming but it doesn't comply.)

  ### Local development with Docker

  In order to work with your application locally without actually sending requests
  to AWS and using credit, you can run a local instance.

  See [Local AWS Development with SAM](zk/Local_AWS_development_with_SAM.md).

  ### Deploy

  Once you have packaged the app you can deploy with `sam deploy --guided`. This
  will talk you through the defaults and will deploy the package to
  CloudFormation. In CloudFormation each individual project is called a **stack**.

  If we then go to Cloud Formation we will see the deployed application.

  ![](/img/cloud-formation-stack.png)

  ## Call the endpoint

  If we now go to the Lambda console, we will see our function listed, and the API
  Gateway endpoint under `triggers`:

  ![](/img/gateway-trigger.png)

  We can then call this from Postman to check everything is working as it should:

  ![](/img/postman-aws-output.png)

raw_content:
  ---
  tags: [AWS]
  ---

  # AWS SAM

  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

  The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
  SAM syntax gets transformed into CloudFormation during the deployment process.
  (CloudFormation is a broader and more robust AWS tool for large, highly
  scaleable infrastructures).

  ## Key features of SAM

  - Single deployment configuration
  - Integration with development tools
  - Local testing and debugging
  - Built on AWS CloudFormation

  ## Main technologies required

  ### Docker

  Whilst SAM can be used to create a deployable file for AWS it can also be run as
  a container for local development with Docker.

  ### AWS CLI

  This is installed using Python and allows you to interact directly with AWS via
  the command-line.

  ### AWS SAM CLI

  See
  [https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)

  ## Setting up credentials for the AWS CLI

  You require an access key for the given
  [IAM user](zk/AWS_User_management_and_roles.md#iam). You should create an IAM
  account specific to the project with bounded permissions.

  ```
  aws configure
  AWS Access Key ID [None]: AK*******
  AWS Secret Access Key [None]: ukp******
  Default region name [None]:
  Default output format [None]:
  ```

  This information can be found in the Security Credentials section of the given
  [IAM](zk/AWS_User_management_and_roles.md#iam) user:

  ![](/img/access-key-aws.png)

  ### Switching between credentials

  You should set up a different IAM user for each project.

  You can do this with:

  ```sh
  aws configure --profile <profile-name>
  ```

  This will then ask you to add the credentials for the user.

  You can switch between different credentials for the user as follows:

  ```sh
  AWS_PROFILE=<profile-name> sam build

  ```

  ## Starting a SAM project

  First create a directory for your project which will serve as the repository:

  ```sh
  mkdir aws-sam-learning
  cd aws-sam-learning
  ```

  Then we can use the `sam` cli to bootstrap the project:

  ```sh
  sam init --runtime nodejs16.x
  ```

  We can just click through and accept the basic HelloWorld Lambda.

  This will create the Lambda as well as an API Gateway trigger URL.

  ### `template.yaml`

  This is autogenerated and details the main constituents of the project. There
  are lots of fields but the most important are the following:

  ```yaml
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
  ```

  This details the location of the [handler function](/Lambda_handler_function.md)
  which is contained at the path `hello-world/app.js`:

  ```js
  exports.lambdaHandler = async (event, context) => {
    try {
      // const ret = await axios(url);
      response = {
        statusCode: 200,
        body: JSON.stringify({
          message: "hello world",
          // location: ret.data.trim()
        }),
      };
    } catch (err) {
      console.log(err);
      return err;
    }

    return response;
  };
  ```

  It also lists the `get` event that we can use to call API Gateway and trigger
  the Lambda.

  The full template is below:

  ![](/img/sam-template-yaml.png)

  ## Adding our own code

  We will create our own function and API Gateway trigger.

  We will place our function after the existing `HelloWorldFunction`

  ```yaml
  ClockFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: clock/
      Handler: handler.clock
      Runtime: nodejs16.x
    Events:
      ClockApi:
        Type: Api
        Properties:
          Path: /clock
          Method: get
  ```

  We can test the syntax with:

  ```sh
  sam validate
  ```

  Just like with `HelloWorld`, we will create a directory for this function:
  `clock` and we will initialise it as an `npm` project.

  ```sh
  mkdir clock
  cd clock
  npm init
  ```

  We will use `handler.js` as our root, handler function.

  We have said in the template file that our `Handler: handler.clock`, therefore
  the main function in the `handler` module should be `clock`:

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

  exports.clock = async (event) => {
    console.log("Clock function run");
    const message = moment().format();
    const response = {
      statusCode: 200,
      body: JSON.stringify(message),
    };
    return response;
  };
  ```

  The directory structure is as follows:

  ![](/_img/sam-directory.png)

  When we call the API Gateway path `/clock` with `GET`, our function will be
  triggered.

  ## Deploying the project

  We will now deploy our project to AWS from the local environment.

  The process is as follows:

  1. Build
  2. Package
  3. Deploy

  ### Build

  We need to install the runtime dependencies for the function. We do this by
  running `sam build`. This ignores test files and development dependencies and
  installs the project dependencies and source files to a temporary subdirectory.

  ![](/img/sam-build.png)

  The build directory is `.aws-sam/build/`. There will be a subdirectory for each
  of our files.

  ### Package

  As noted, CloudFront handles the deployment of the application. It can only
  receive one file as an input. The packaging process consists in creating that
  single file.

  The packaging proces will first archive all of the project artefacts into a zip
  file and then upload that to [S3](zk/AWS_S3.md). A reference to this S3 entity
  is then provided to CloudFormation.

  ![](/img/s3-package-again.svg)

  The command is as follows:

  ```sh
  sam package
    --template-file template.yaml
    --output-template-file pkg.yml
    --region eu-west-1
  ```

  This will automatically create a hashed bucket name for you in S3 (I have tried
  to add my own naming but it doesn't comply.)

  ### Local development with Docker

  In order to work with your application locally without actually sending requests
  to AWS and using credit, you can run a local instance.

  See [Local AWS Development with SAM](zk/Local_AWS_development_with_SAM.md).

  ### Deploy

  Once you have packaged the app you can deploy with `sam deploy --guided`. This
  will talk you through the defaults and will deploy the package to
  CloudFormation. In CloudFormation each individual project is called a **stack**.

  If we then go to Cloud Formation we will see the deployed application.

  ![](/img/cloud-formation-stack.png)

  ## Call the endpoint

  If we now go to the Lambda console, we will see our function listed, and the API
  Gateway endpoint under `triggers`:

  ![](/img/gateway-trigger.png)

  We can then call this from Postman to check everything is working as it should:

  ![](/img/postman-aws-output.png)


path: zk/Schema_Definition_Language.md
sortable_path: zkSchema_Definition_Language.md
title: Schema Definition Language
lead: SDL is the formal name for the syntax of GraphQL schemas.
checksum: c50d5b10c7f9a915e1d4d5d9bb67ef337b59f126f97bfda5c6bfeba74d25ac1c
created: 2024-03-30 09:03:21.043334122+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["graphql"]}
body:
  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
  """
  ```

raw_content:
  ---
  tags: [graphql]
  ---

  # 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
  """
  ```


path: zk/Secrets_or_env_vars.md
sortable_path: zkSecrets_or_env_vars.md
title: Secrets or environment variables?
checksum: 5dbb25aea37698bb6cf861e39dfd15ee9823b0e0e928f76e9d1d4e3899538a9b
created: 2024-03-30 09:03:21.04733042+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS","aws-lambda"]}
lead:
  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

body:
  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

  General recommendations suggest using AWS Secrets Manager for storing sensitive
  data like API keys and passwords, due to its enhanced security features. For
  less sensitive, non-critical data such as feature flags or environment-specific
  URLs, environment variables are often adequate. Cost-conscious users who don't
  need advanced features may find environment variables more economical.
  Ultimately, the best choice depends on your specific requirements and
  limitations.

raw_content:
  ---
  tags: [AWS, aws-lambda]
  ---

  # Secrets or environment variables?

  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

  General recommendations suggest using AWS Secrets Manager for storing sensitive
  data like API keys and passwords, due to its enhanced security features. For
  less sensitive, non-critical data such as feature flags or environment-specific
  URLs, environment variables are often adequate. Cost-conscious users who don't
  need advanced features may find environment variables more economical.
  Ultimately, the best choice depends on your specific requirements and
  limitations.


path: zk/Semantic_versioning.md
sortable_path: zkSemantic_versioning.md
title: Semantic versioning
lead:
  ```
  3.4.1 === major.minor.patch
  ```

checksum: 594b1e9ce9125afba02b6d41efe4af9a53aff06bff3ab7739bc2e89e65f6d664
created: 2024-03-30 09:03:21.052315622+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":[]}
body:
  ```
  3.4.1 === major.minor.patch
  ```

  - Major

    - New feature which may potentially cause breaking changes to applications
      dependent on the previous major version.

  - Minor

    - New features that do not break the existing API

  - Patch

    - Bug fixes for the current minor version

  ## Glob patterns for versioning

  ### Caret

  Interested in any version so long as the major version remains at $n$. E.g if we
  are at `^4.2.1` and we upgrade, we are ok with `4.5.3` or `4.8.2`. We are not
  bothered about the minor or patch version.

  This is equivalent to `4.x`

  ### Tilde

  Interested in any patch version within set major and minor parameters. For
  example `~1.8.3` means you don't mind any patch version so long as it is a patch
  for `1.8`. This is equivalent to `1.8.x`.

  ### No tilde or caret

  Use the _exact_ version specified

raw_content:
  ---
  tags: []
  ---

  # Semantic versioning

  ```
  3.4.1 === major.minor.patch
  ```

  - Major

    - New feature which may potentially cause breaking changes to applications
      dependent on the previous major version.

  - Minor

    - New features that do not break the existing API

  - Patch

    - Bug fixes for the current minor version

  ## Glob patterns for versioning

  ### Caret

  Interested in any version so long as the major version remains at $n$. E.g if we
  are at `^4.2.1` and we upgrade, we are ok with `4.5.3` or `4.8.2`. We are not
  bothered about the minor or patch version.

  This is equivalent to `4.x`

  ### Tilde

  Interested in any patch version within set major and minor parameters. For
  example `~1.8.3` means you don't mind any patch version so long as it is a patch
  for `1.8`. This is equivalent to `1.8.x`.

  ### No tilde or caret

  Use the _exact_ version specified


path: zk/Sets_in_Python.md
sortable_path: zkSets_in_Python.md
title: Sets in Python
checksum: 766c8d1f8a0736bf3d4e5e1f15ba881fe068dd8f6f2b0d8888c184a25608328a
created: 2024-03-30 09:03:21.057134408+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-structures"]}
lead:
  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

body:
  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

  > Sets are denoted with `{...}`

  ## Basic usage

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print(basket)  # show that duplicates have been removed
  print(len(basket))
  # {'apple', 'pear', 'banana', 'orange'}
  # 4
  ```

  ## Looping through sets

  ```python
  for item in basket:
      print(item)

  """
  apple
  pear
  banana
  orange
  """
  ```

  ## Check for membership

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print('apple' in basket)
  # True
  ```

  ## Remove items from set

  > `remove` will raise an error if the specified item does not exist, `discard`
  > will not

  ```python
  basket.remove('apple')
  basket.discard('apricot')
  print(basket)
  # {'pear', 'banana', 'orange'}

  basket.clear()
  print(basket)
  #set

  ```

  ## Add items to a set

  ```python
  basket.add('apricot')
  print(basket)
  # {'apricot', 'pear', 'banana', 'orange'}
  ```

  ## Start with empty set

  To declare an empty set you cannot just do:

  ```py
  my_set = {}
  ```

  You have to use a constructor:

  ```py
  my_set = set()
  ```

  ## Apply unions and intersections

  ```python
  s1 = {'apple', 'orange', 'banana'}
  s2 = {'grapefruit', 'lime', 'banana'}
  print('Union:', s1 | s2)
  # Union: {'apple', 'orange', 'grapefruit', 'lime', 'banana'}

  print('Intersection:', s1 & s2)
  # Intersection: {'banana'}


  print('Difference:', s1 - s2)
  # Difference: {'orange', 'apple'}

  print('Symmetric Difference:', s1 ^ s2)
  #Symmetric Difference: {'apple', 'orange', 'grapefruit', 'lime'}

  ```

raw_content:
  ---
  tags: [python, data-structures]
  ---

  # Sets in Python

  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

  > Sets are denoted with `{...}`

  ## Basic usage

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print(basket)  # show that duplicates have been removed
  print(len(basket))
  # {'apple', 'pear', 'banana', 'orange'}
  # 4
  ```

  ## Looping through sets

  ```python
  for item in basket:
      print(item)

  """
  apple
  pear
  banana
  orange
  """
  ```

  ## Check for membership

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print('apple' in basket)
  # True
  ```

  ## Remove items from set

  > `remove` will raise an error if the specified item does not exist, `discard`
  > will not

  ```python
  basket.remove('apple')
  basket.discard('apricot')
  print(basket)
  # {'pear', 'banana', 'orange'}

  basket.clear()
  print(basket)
  #set

  ```

  ## Add items to a set

  ```python
  basket.add('apricot')
  print(basket)
  # {'apricot', 'pear', 'banana', 'orange'}
  ```

  ## Start with empty set

  To declare an empty set you cannot just do:

  ```py
  my_set = {}
  ```

  You have to use a constructor:

  ```py
  my_set = set()
  ```

  ## Apply unions and intersections

  ```python
  s1 = {'apple', 'orange', 'banana'}
  s2 = {'grapefruit', 'lime', 'banana'}
  print('Union:', s1 | s2)
  # Union: {'apple', 'orange', 'grapefruit', 'lime', 'banana'}

  print('Intersection:', s1 & s2)
  # Intersection: {'banana'}


  print('Difference:', s1 - s2)
  # Difference: {'orange', 'apple'}

  print('Symmetric Difference:', s1 ^ s2)
  #Symmetric Difference: {'apple', 'orange', 'grapefruit', 'lime'}

  ```


path: zk/Setup_configuration.md
sortable_path: zkSetup_configuration.md
title: Setup and configuration
lead: ## Installation and configuration
checksum: 7ad962fc516dcea03815580140ae449dfaeb4c74b9e330cc4b8199af5454edf1
created: 2024-03-30 09:03:21.062227848+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["typescript"]}
body:
  ## Installation and configuration

  TypeScript offers custom installations for most modern JS-based frameworks
  including Webpack, React.js and Vue.js. The instructions below cover minimal TS
  set-up outside of a specific framework. TypeScript adds an additional step to
  any build process since your code must compile to JS before any bundling and
  transpilation can occur.

  ## Installation

  ```
  mkdir typescript-project
  cd typescript-project
  npm i typescript --save-dev
  ```

  ## Initialise project

  ```
  npx tsc --init
  ```

  ## Basic configuration

  ```json
  "compilerOptions": {
  	"target" : "es2020", //es2015 for prod
  	"module" : "es2020",
    	"allowJs": true,
    	"checkJs": true,
    	"strict": true,
    	"esModuleInterop": true
  }
  ```

  ### Specify output paths (for production code)

  ```json
  "compilerOptions": {
  	...
  	"outDir": "dist",
  	"sourceMap": true,
  }
  ```

  ### Compile-time commands

  ```
  tsc --noEmit
  ```

  ```
  tsc --noEmit --watch
  ```

  ## Global requirements

  ```
  npm install -g typescript
  npm install -g ts-node
  ```

  `ts-node` allows you to run TS files the way you would with standard JS, i.e.
  `node [filename]`, you just use `ts-node filename` .

  This is a convenience that saves you compiling from TS → JS and then running
  Node against the compiled JS. Which is useful for debugging and checking values
  as you work.

  ## Imports and exports

  You may wish to define your custom types outside of their application, for
  instance in a `/types/` directory. The custom type or types can then be imported
  using standard ES6 imports:

  ```tsx
  export type Article = {
  		price: number,
  }

  export type AnotherType = {
  ...
  }
  ```

  ```tsx
  import { Article, AnotherType } from "./types/allTypes.js";
  import Article from "./types/allTypes.js";
  ```

  TypeScript also provides a specific import keyword `type` so that you can
  distinguish type imports from other module imports. This is handy when you have
  multiple components in the one file:

  ```tsx
  import type { Article } from "./types/allTypes.js";
  ```

raw_content:
  ---
  tags:
    - typescript
  ---

  # Setup and configuration

  ## Installation and configuration

  TypeScript offers custom installations for most modern JS-based frameworks
  including Webpack, React.js and Vue.js. The instructions below cover minimal TS
  set-up outside of a specific framework. TypeScript adds an additional step to
  any build process since your code must compile to JS before any bundling and
  transpilation can occur.

  ## Installation

  ```
  mkdir typescript-project
  cd typescript-project
  npm i typescript --save-dev
  ```

  ## Initialise project

  ```
  npx tsc --init
  ```

  ## Basic configuration

  ```json
  "compilerOptions": {
  	"target" : "es2020", //es2015 for prod
  	"module" : "es2020",
    	"allowJs": true,
    	"checkJs": true,
    	"strict": true,
    	"esModuleInterop": true
  }
  ```

  ### Specify output paths (for production code)

  ```json
  "compilerOptions": {
  	...
  	"outDir": "dist",
  	"sourceMap": true,
  }
  ```

  ### Compile-time commands

  ```
  tsc --noEmit
  ```

  ```
  tsc --noEmit --watch
  ```

  ## Global requirements

  ```
  npm install -g typescript
  npm install -g ts-node
  ```

  `ts-node` allows you to run TS files the way you would with standard JS, i.e.
  `node [filename]`, you just use `ts-node filename` .

  This is a convenience that saves you compiling from TS → JS and then running
  Node against the compiled JS. Which is useful for debugging and checking values
  as you work.

  ## Imports and exports

  You may wish to define your custom types outside of their application, for
  instance in a `/types/` directory. The custom type or types can then be imported
  using standard ES6 imports:

  ```tsx
  export type Article = {
  		price: number,
  }

  export type AnotherType = {
  ...
  }
  ```

  ```tsx
  import { Article, AnotherType } from "./types/allTypes.js";
  import Article from "./types/allTypes.js";
  ```

  TypeScript also provides a specific import keyword `type` so that you can
  distinguish type imports from other module imports. This is handy when you have
  multiple components in the one file:

  ```tsx
  import type { Article } from "./types/allTypes.js";
  ```


path: zk/Shell_sessions.md
sortable_path: zkShell_sessions.md
title: Types of shell session
lead: Shell sessions can be one of or several instances of the following types:
checksum: ad767e5e8a1da625e334027c1d032d013d525f32f51136c4da9038b054719c23
created: 2024-03-30 09:03:21.071997795+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  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`

raw_content:
  ---
  tags:
    - shell
  ---

  ## **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`


path: zk/Signed_and_unsigned_numbers.md
sortable_path: zkSigned_and_unsigned_numbers.md
title: Signed and unsigned numbers
lead: ## Summary
checksum: 0dd060a4662e8b9daf6a58073529520afc171a28313f6d60e2b57179598a782c
created: 2024-03-30 09:03:21.09131187+00:00
modified: 2024-06-15 09:55:22.808856089+00:00
metadata: {"tags":["binary"]}
body:
  ## 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]]

raw_content:
  ---
  tags:
    - binary
  ---

  # 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]]


path: zk/Signed_magnitude_representation.md
sortable_path: zkSigned_magnitude_representation.md
title: Signed_magnitude_representation
lead: # Signed magnitude representation
checksum: ee209d1ba4c56934bbbff4de0a72a1e82652208c9ea9cab1e11677ecebd446cc
created: 2024-03-30 09:03:21.124300039+00:00
modified: 2024-06-15 09:55:28.71896598+00:00
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]]

raw_content:
  ---
  id: 3wsh
  title: Signed_magnitude_representation
  tags:
    - binary
  created: Wednesday, March 20, 2024
  ---

  # 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]]

metadata:
  {"created":"Wednesday, March 20, 2024","id":"3wsh","tags":["binary"],"title":"Signed_magnitude_representation"}


path: zk/Singleton_pattern.md
sortable_path: zkSingleton_pattern.md
title: Singleton pattern
checksum: 8be5ec8f9b2ec01c4f4af510138186db2412e24c5353621075b4c7b81aebfd87
created: 2024-03-30 09:03:21.135311993+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["OOP"]}
lead:
  As the name suggests, the Singleton pattern is best used in scenarios where you
  only want to use a single, unique instance of a class. This is for functionality
  that should only be executed once in the lifecycle of an application. The
  canonical case would be some kind of bootstrapping process required at
  initialisation, or initial configuration for an app.

body:
  As the name suggests, the Singleton pattern is best used in scenarios where you
  only want to use a single, unique instance of a class. This is for functionality
  that should only be executed once in the lifecycle of an application. The
  canonical case would be some kind of bootstrapping process required at
  initialisation, or initial configuration for an app.

  ## Use-cases

  - Establishing connection to backend database
  - API connection (managing tokens so that you are not sending multiple
    unnecessary calls)
  - Configuration settings for an app
  - Global state stores in Redux and the React Context API

  > With this pattern only one instance of the class can exist. If no instance of
  > the singleton class exists then a new instance is created and returned, but if
  > an instance already exists, then the reference to the existing instance is
  > returned. A singleton should be immutable by the consuming code, and there
  > should be no danger of instantiating more than one of them.

  ## Implementation

  This pattern can be implemented either with a object or a class.

  In the example below, a global store for a modern JS application is created
  using an object.

  ### Using an object

  We ensure singularity by:

  - using `const` for the object so that it cannot be reassigned
  - using `Object.freeze` so that the fields cannot be overwritten, deleted, or
    additional fields added

  ```js
  const _data = [];

  // Methods to add and retrieve data from the store
  const UserStore = {
    add: (item) => _data.push(item),
    get: (id) => _data.find((d) => d.id === id),
  };

  Object.freeze(UserStore);
  export default UserStore;
  ```

  ### Using a class

  The same process can be created using classes:

  ```js
  class UserStore {
    constructor() {
      this._data = [];
    }

    add(item) {
      this._data.push(item);
    }

    get(id) {
      return this._data.find((d) => d.id === id);
    }
  }

  const instance = new UserStore();
  Object.freeze(instance);

  export default instance;
  ```

  Bear in mind that this is really just an ES6 module with `freeze` applied. The
  only real difference between a singleton and a module is that there should only
  be one instance of it.

  With classes, there is a further step that can be taken to prevent more than
  once instance of the class being created. This is necessary if you want to be
  really strict because it is of course possible for a well motivated person to
  get around the safeguards we established above. We do this by having the class
  itself check whether there is already an instance of itself. If so, it just
  returns the already existing instance. We do this by using the self-reference
  inherent in `this` :

  ```jsx
  class UserStore {
    constructor() {
      if (!UserStore.instance) {
        this._data = [];
        UserStore.instance = this;
      }

      return UserStore.instance;
    }

    //rest is the same code as preceding example
  }

  const instance = new UserStore();
  Object.freeze(instance);

  export default instance;
  ```

raw_content:
  ---
  tags: [OOP]
  ---

  # Singleton pattern

  As the name suggests, the Singleton pattern is best used in scenarios where you
  only want to use a single, unique instance of a class. This is for functionality
  that should only be executed once in the lifecycle of an application. The
  canonical case would be some kind of bootstrapping process required at
  initialisation, or initial configuration for an app.

  ## Use-cases

  - Establishing connection to backend database
  - API connection (managing tokens so that you are not sending multiple
    unnecessary calls)
  - Configuration settings for an app
  - Global state stores in Redux and the React Context API

  > With this pattern only one instance of the class can exist. If no instance of
  > the singleton class exists then a new instance is created and returned, but if
  > an instance already exists, then the reference to the existing instance is
  > returned. A singleton should be immutable by the consuming code, and there
  > should be no danger of instantiating more than one of them.

  ## Implementation

  This pattern can be implemented either with a object or a class.

  In the example below, a global store for a modern JS application is created
  using an object.

  ### Using an object

  We ensure singularity by:

  - using `const` for the object so that it cannot be reassigned
  - using `Object.freeze` so that the fields cannot be overwritten, deleted, or
    additional fields added

  ```js
  const _data = [];

  // Methods to add and retrieve data from the store
  const UserStore = {
    add: (item) => _data.push(item),
    get: (id) => _data.find((d) => d.id === id),
  };

  Object.freeze(UserStore);
  export default UserStore;
  ```

  ### Using a class

  The same process can be created using classes:

  ```js
  class UserStore {
    constructor() {
      this._data = [];
    }

    add(item) {
      this._data.push(item);
    }

    get(id) {
      return this._data.find((d) => d.id === id);
    }
  }

  const instance = new UserStore();
  Object.freeze(instance);

  export default instance;
  ```

  Bear in mind that this is really just an ES6 module with `freeze` applied. The
  only real difference between a singleton and a module is that there should only
  be one instance of it.

  With classes, there is a further step that can be taken to prevent more than
  once instance of the class being created. This is necessary if you want to be
  really strict because it is of course possible for a well motivated person to
  get around the safeguards we established above. We do this by having the class
  itself check whether there is already an instance of itself. If so, it just
  returns the already existing instance. We do this by using the self-reference
  inherent in `this` :

  ```jsx
  class UserStore {
    constructor() {
      if (!UserStore.instance) {
        this._data = [];
        UserStore.instance = this;
      }

      return UserStore.instance;
    }

    //rest is the same code as preceding example
  }

  const instance = new UserStore();
  Object.freeze(instance);

  export default instance;
  ```


path: zk/Sliding_window.md
sortable_path: zkSliding_window.md
title: Sliding window
checksum: abd859e6151ba1932dd5ab3f4e7ad9bd13b6122890882b9981aaa1d7ac860479
created: 2024-03-30 09:03:21.140319034+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":[]}
lead:
  Whereas the [multiple pointer](Multiple_pointers.md) pattern works by keeping
  two array indices running at once and comparing their values on each iteration,
  the sliding window has a running value (the 'window') that is updated at each
  iteration and which compares itself against its most recent previous value.

body:
  Whereas the [multiple pointer](Multiple_pointers.md) pattern works by keeping
  two array indices running at once and comparing their values on each iteration,
  the sliding window has a running value (the 'window') that is updated at each
  iteration and which compares itself against its most recent previous value.

  This is what makes it 'sliding': the value isn't constant, it changes (or
  doesn't) based on what it was previously.

  ## Example: maximum sum of sub-array

  We create a function that takes an array and a sub-array length _n_. The
  objective is to find the maximum value that can be created by summing _n_
  elements of the array. It moves through the array, summing by _n_ keeping track
  of the highest sum value so far and the current sum value. At the end it should
  return the highest possible sum value.

  Here we do this for a sub-array of length 2:

  ```ts
  function maxSubarraySum(arr, subArrLength) {
    let maxSum = 0; // Largest sum value so far
    let tempSum = 0; // Current sum value

    //  Establish the first 'maxSum'
    // At the beginning this will just be the sum of the first two array elements
    for (let i = 0; i < subArrLength; i++) {
      maxSum += arr[i];
    }

    // Map temporary sum to maxSum
    // Accordingly, as we have only mapped the first sub-array, the max sum will be the same
    // as the current sum
    tempSum = maxSum;

    // Move through the array one element at a time (`i++`) via a window starting from the element that is equal to `subArrLength`
    // The first sum calculation is already taken care of in the earlier loop and stored in `maxSum`, so we don't have to worry about missing the elements in indices less than subArrLength
    for (let i = subArrLength; i < arr.length; i++) {
      // Temp sum becomes a moveable window value equal to the subtraction of the previous element and the addition of next element in line
      tempSum = tempSum - arr[i - subArrLength] + arr[i];
      // Max sum is redefined as the largest subArrLengthber between the previous highest and the current value of tempSum
      maxSum = Math.max(maxSum, tempSum);
    }
    return maxSum;
  }

  console.log(maxSubarraySum([100, 200, 300, 400], 2)); // 700
  ```

raw_content:
  ---
  tags: []
  ---

  # Sliding window

  Whereas the [multiple pointer](Multiple_pointers.md) pattern works by keeping
  two array indices running at once and comparing their values on each iteration,
  the sliding window has a running value (the 'window') that is updated at each
  iteration and which compares itself against its most recent previous value.

  This is what makes it 'sliding': the value isn't constant, it changes (or
  doesn't) based on what it was previously.

  ## Example: maximum sum of sub-array

  We create a function that takes an array and a sub-array length _n_. The
  objective is to find the maximum value that can be created by summing _n_
  elements of the array. It moves through the array, summing by _n_ keeping track
  of the highest sum value so far and the current sum value. At the end it should
  return the highest possible sum value.

  Here we do this for a sub-array of length 2:

  ```ts
  function maxSubarraySum(arr, subArrLength) {
    let maxSum = 0; // Largest sum value so far
    let tempSum = 0; // Current sum value

    //  Establish the first 'maxSum'
    // At the beginning this will just be the sum of the first two array elements
    for (let i = 0; i < subArrLength; i++) {
      maxSum += arr[i];
    }

    // Map temporary sum to maxSum
    // Accordingly, as we have only mapped the first sub-array, the max sum will be the same
    // as the current sum
    tempSum = maxSum;

    // Move through the array one element at a time (`i++`) via a window starting from the element that is equal to `subArrLength`
    // The first sum calculation is already taken care of in the earlier loop and stored in `maxSum`, so we don't have to worry about missing the elements in indices less than subArrLength
    for (let i = subArrLength; i < arr.length; i++) {
      // Temp sum becomes a moveable window value equal to the subtraction of the previous element and the addition of next element in line
      tempSum = tempSum - arr[i - subArrLength] + arr[i];
      // Max sum is redefined as the largest subArrLengthber between the previous highest and the current value of tempSum
      maxSum = Math.max(maxSum, tempSum);
    }
    return maxSum;
  }

  console.log(maxSubarraySum([100, 200, 300, 400], 2)); // 700
  ```


path: zk/Solving_equations.md
sortable_path: zkSolving_equations.md
title: Use inversion of operators
checksum: 099dc6ccac9ebaf46912c22e7c3d66c05765a3b22823924cb085489d6bf67af7
created: 2024-03-30 09:03:21.150362187+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["algebra"]}
lead:
  When solving equations we frequently make use of the
  [ operator inversion rules](Inversion%20of%20operators.md) to find
  the solutions.

body:
  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$$

raw_content:
  ---
  tags: [algebra]
  ---

  ## 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$$


path: zk/Sorting_lists_in_Python.md
sortable_path: zkSorting_lists_in_Python.md
title: Sorting lists in Python
lead: ### Using `sorted()` Function:
checksum: ac48196d81b67d9d944918b8fa4b520193798f40404205ad6e31b34dec410986
created: 2024-03-30 09:03:21.164687713+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python"]}
body:
  ### Using `sorted()` Function:

  The built-in `sorted()` function returns a new list containing all the elements
  of the original list sorted in the specified order (either ascending, which is
  default, or descending).

  ```python
  my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
  sorted_list = sorted(my_list)
  print(sorted_list)  # Output: [1, 1, 2, 3, 4, 5, 5, 6, 9]
  ```

  For sorting in descending order, you can use the `reverse=True` argument:

  ```python
  sorted_list_desc = sorted(my_list, reverse=True)
  print(sorted_list_desc)  # Output: [9, 6, 5, 5, 4, 3, 2, 1, 1]
  ```

  ### Using `.sort()` Method:

  The `.sort()` method sorts the elements of a list in-place and returns `None`.
  This modifies the original list.

  ```python
  my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
  my_list.sort()
  print(my_list)  # Output: [1, 1, 2, 3, 4, 5, 5, 6, 9]
  ```

  For sorting in descending order:

  ```python
  my_list.sort(reverse=True)
  print(my_list)  # Output: [9, 6, 5, 5, 4, 3, 2, 1, 1]
  ```

  ### Using a Custom Key Function:

  Both `sorted()` and `.sort()` accept a `key` parameter that allows you to
  specify a function to determine the sorting order. The function should take a
  single argument and return a value that will be used for sorting purposes.

  For example, if you have a list of strings and you want to sort them by their
  length:

  ```python
  my_str_list = ["apple", "banana", "cherry", "date"]
  sorted_by_length = sorted(my_str_list, key=len)
  print(sorted_by_length)  # Output: ['date', 'apple', 'cherry', 'banana']
  ```

raw_content:
  ---
  tags: [python]
  ---

  # Sorting lists in Python

  ### Using `sorted()` Function:

  The built-in `sorted()` function returns a new list containing all the elements
  of the original list sorted in the specified order (either ascending, which is
  default, or descending).

  ```python
  my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
  sorted_list = sorted(my_list)
  print(sorted_list)  # Output: [1, 1, 2, 3, 4, 5, 5, 6, 9]
  ```

  For sorting in descending order, you can use the `reverse=True` argument:

  ```python
  sorted_list_desc = sorted(my_list, reverse=True)
  print(sorted_list_desc)  # Output: [9, 6, 5, 5, 4, 3, 2, 1, 1]
  ```

  ### Using `.sort()` Method:

  The `.sort()` method sorts the elements of a list in-place and returns `None`.
  This modifies the original list.

  ```python
  my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
  my_list.sort()
  print(my_list)  # Output: [1, 1, 2, 3, 4, 5, 5, 6, 9]
  ```

  For sorting in descending order:

  ```python
  my_list.sort(reverse=True)
  print(my_list)  # Output: [9, 6, 5, 5, 4, 3, 2, 1, 1]
  ```

  ### Using a Custom Key Function:

  Both `sorted()` and `.sort()` accept a `key` parameter that allows you to
  specify a function to determine the sorting order. The function should take a
  single argument and return a value that will be used for sorting purposes.

  For example, if you have a list of strings and you want to sort them by their
  length:

  ```python
  my_str_list = ["apple", "banana", "cherry", "date"]
  sorted_by_length = sorted(my_str_list, key=len)
  print(sorted_by_length)  # Output: ['date', 'apple', 'cherry', 'banana']
  ```


path: zk/Soundness.md
sortable_path: zkSoundness.md
title: Soundness
checksum: d7502906245e61759a05792bb1ac1529a125a95843565c46f58eb1f289042564
created: 2024-03-30 09:03:21.16931637+00:00
modified: 2024-06-16 16:52:50.657513956+00:00
metadata: {"tags":["propositional-logic","logic"]}
lead:
  Recall that in the definition of
  [deductive validity](Validity_and_entailment.md#validity)
  we do not say: an argument is valid iff if the premises _are true_ and the
  conclusion _is true_. We say _if it is possible for the premises to be true_.
  This is important: we are not interested in the actual truth of the premises or
  the conclusion.

body:
  Recall that in the definition of
  [deductive validity](Validity_and_entailment.md#validity)
  we do not say: an argument is valid iff if the premises _are true_ and the
  conclusion _is true_. We say _if it is possible for the premises to be true_.
  This is important: we are not interested in the actual truth of the premises or
  the conclusion.

  #### Demonstration

  Therefore this argument is valid:

  ```
  (P1) Oranges are the same colour as bananas.
  (P2) Bananas are yellow.
  ____________________________________________
  (C) Oranges are yellow.
  ```

  Of course oranges are not yellow but _were_ (P1) true, then given (P2), the
  conclusion must also be true.

  This argument is also valid:

  ```
  (P1) Oranges are the same colour as carrots.
  (P2) Carrots are orange.
  ____________________________________________
  (C) Oranges are orange in colour.
  ```

  The difference here is that the premises happen to be true and, given that the
  argument is valid, the conclusion must also be true. What we have defined here
  is **soundness**: the argument is said to be sound as well as valid. This is an
  additional and stronger criterion of evaluation.

  > An argument is sound if and only if it is deductively valid and all its
  > premises are true.

  We must not forget that truth alone is not the sole condition for soundness. We
  can have arguments whose conclusion and premises are all true without the
  argument being sound:

  ```
  (P1) London is the capital of the United Kingdom
  (P2) The capital of the United Kingdom is in the southern part of the United Kingdom.
  (P3) Cambridge is not the capital of the United Kingdom
  ____________________________________________
  (C) London is south of Cambridge
  ```

  All propositions are true here but the argument is not deductively valid: the
  premises are all true but the conclusion is false.

  We can also have arguments which are valid but which are not sound:

  ```
  (P1) Vitamin C prevents colds.
  (P2) Vitamin C does not prevent colds.
  ____________________________________________
  (C) Vitamin C is harmless
  ```

  This argument is valid because we cannot consistently assert the premises and
  deny the conclusion. In either case, the conclusion can be said to follow from
  the premises. The problem is that we cannot consistently assert both premises:
  it is not possible for both propositions to be true at the same time.

raw_content:
  ---
  tags:
    - propositional-logic
    - logic
  ---

  # Soundness

  Recall that in the definition of
  [deductive validity](Validity_and_entailment.md#validity)
  we do not say: an argument is valid iff if the premises _are true_ and the
  conclusion _is true_. We say _if it is possible for the premises to be true_.
  This is important: we are not interested in the actual truth of the premises or
  the conclusion.

  #### Demonstration

  Therefore this argument is valid:

  ```
  (P1) Oranges are the same colour as bananas.
  (P2) Bananas are yellow.
  ____________________________________________
  (C) Oranges are yellow.
  ```

  Of course oranges are not yellow but _were_ (P1) true, then given (P2), the
  conclusion must also be true.

  This argument is also valid:

  ```
  (P1) Oranges are the same colour as carrots.
  (P2) Carrots are orange.
  ____________________________________________
  (C) Oranges are orange in colour.
  ```

  The difference here is that the premises happen to be true and, given that the
  argument is valid, the conclusion must also be true. What we have defined here
  is **soundness**: the argument is said to be sound as well as valid. This is an
  additional and stronger criterion of evaluation.

  > An argument is sound if and only if it is deductively valid and all its
  > premises are true.

  We must not forget that truth alone is not the sole condition for soundness. We
  can have arguments whose conclusion and premises are all true without the
  argument being sound:

  ```
  (P1) London is the capital of the United Kingdom
  (P2) The capital of the United Kingdom is in the southern part of the United Kingdom.
  (P3) Cambridge is not the capital of the United Kingdom
  ____________________________________________
  (C) London is south of Cambridge
  ```

  All propositions are true here but the argument is not deductively valid: the
  premises are all true but the conclusion is false.

  We can also have arguments which are valid but which are not sound:

  ```
  (P1) Vitamin C prevents colds.
  (P2) Vitamin C does not prevent colds.
  ____________________________________________
  (C) Vitamin C is harmless
  ```

  This argument is valid because we cannot consistently assert the premises and
  deny the conclusion. In either case, the conclusion can be said to follow from
  the premises. The problem is that we cannot consistently assert both premises:
  it is not possible for both propositions to be true at the same time.


path: zk/Split_into_array.md
sortable_path: zkSplit_into_array.md
title: Splitting input into an array
lead: ## readarray
checksum: b613cfe6a16f00e820880c671aeeccbf3f0ecdae9e3770fc68016d7b50c6b413
created: 2024-03-30 09:03:21.18350543+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ## 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.

raw_content:
  ---
  tags:
    - shell
  ---

  # 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.


path: zk/Stacks.md
sortable_path: zkStacks.md
title: A stack is a linear data structure that observes LIFO
checksum: a141ae765f7298ff9bd03a8d68bdae6ac6ac56e84d1369198460bc254462f9a8
created: 2024-03-30 09:03:21.188736548+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["data-structures"]}
lead:
  Think of a stack like a pile of books: the last book that you add is the nearest
  to the top and therefore the first one that you can remove.

body:
  Think of a stack like a pile of books: the last book that you add is the nearest
  to the top and therefore the first one that you can remove.

  If you want to get a book that is not at the top, you have to first remove the
  books that are above it to get to it.

  This type of data structure is linear and only allows sequential, not random,
  access. It is an example of 'last one in first one out'.

  ## We can build a stack from an array

  A stack is an example of a data structure that can be built by adapting an
  array. If you think about it, all that is needed is an array to store the data,
  an `array push` method to add elements to the 'end' or the 'bottom' of the stack
  and an `array pop` method to remove the element at the top.

  ## Demonstration

  Below we create a stack constructor, using a class. An object created from this
  template will have the following properties and methods:

  - `items[]` → an array to store the data
  - `push()` → a method to add an element to the end of the stack
  - `pop()` → a method to remove an element from the front

  In addition we have the following helpers, which allow us to check the status of
  the stack and retrieve information about it:

  - `isEmpty()` → check if the stack is populated or not
  - `clear()` → empty the stack of its content (therefore making `isEmpty()`
    return `true`)
  - `size` → a property corresponding to the stack's length

  ```js
  class Stack {
    items = []; // the array that will store the elements that comprise the stack
    push = (element) => this.items.push(element); // add an element to the end of the stack
    pop = () => this.items.pop(); // remove and return the last element from the stack

    // We can add some useful helper methods, that return info about the state of the stack:
    isEmpty = () => this.items.length === 0; // return true if the stack is empty
    clear = () => (this.items.length = 0); // empty the stack
    size = () => this.items.length; // count elements in stack
  }
  ```

  ## Run through

  ```js
  let stack = new Stack();
  test.push(1); // Add some elements to the stack
  test.push(2);
  test.push(3);

  // Stack now looks like:
  console.log(stack.items); // [1, 2, 3]

  // Let's try removing the last element
  stack.pop(); // 3 -> this was the last element we added, so it's the first one that comes out

  // Now the stack looks like this:
  // [1,2]

  // Let's add a new element
  test.push(true);

  // Now the stack looks like:
  // [1,2, true]
  ```

  ## Practical applications

  - Any application that wants to got 'back in time' must utilise a stack. For
    example, the 'undo' function in most software is a function of a stack. The
    most recent action is at the top, and under that is the second most recent and
    so on all the way back to the first action.
  - Recursive functions: a function that calls itself repeatedly until a boundary
    condition is met is using a stack structure. As you drill down through the
    function calls you start from the most recent down to the last.
  - Balancing parentheses. Say you want to check if the following string is
    balanced `[()]` . Every time you find an opening parentheses. You push that to
    the front of a stack. You then compare the closing parentheses with the order
    of the stack. The same could be done when seeking to find palindromes. This
    sort of thing could be a code challenge so build an example.

raw_content:
  ---
  tags:
    - data-structures
  ---

  _A stack visualised vertically_ ![stack2.svg](stack2.svg)

  _A stack visualised horizontally_ ![stack1.svg](stack1.svg)

  ## A stack is a linear data structure that observes LIFO

  Think of a stack like a pile of books: the last book that you add is the nearest
  to the top and therefore the first one that you can remove.

  If you want to get a book that is not at the top, you have to first remove the
  books that are above it to get to it.

  This type of data structure is linear and only allows sequential, not random,
  access. It is an example of 'last one in first one out'.

  ## We can build a stack from an array

  A stack is an example of a data structure that can be built by adapting an
  array. If you think about it, all that is needed is an array to store the data,
  an `array push` method to add elements to the 'end' or the 'bottom' of the stack
  and an `array pop` method to remove the element at the top.

  ## Demonstration

  Below we create a stack constructor, using a class. An object created from this
  template will have the following properties and methods:

  - `items[]` → an array to store the data
  - `push()` → a method to add an element to the end of the stack
  - `pop()` → a method to remove an element from the front

  In addition we have the following helpers, which allow us to check the status of
  the stack and retrieve information about it:

  - `isEmpty()` → check if the stack is populated or not
  - `clear()` → empty the stack of its content (therefore making `isEmpty()`
    return `true`)
  - `size` → a property corresponding to the stack's length

  ```js
  class Stack {
    items = []; // the array that will store the elements that comprise the stack
    push = (element) => this.items.push(element); // add an element to the end of the stack
    pop = () => this.items.pop(); // remove and return the last element from the stack

    // We can add some useful helper methods, that return info about the state of the stack:
    isEmpty = () => this.items.length === 0; // return true if the stack is empty
    clear = () => (this.items.length = 0); // empty the stack
    size = () => this.items.length; // count elements in stack
  }
  ```

  ## Run through

  ```js
  let stack = new Stack();
  test.push(1); // Add some elements to the stack
  test.push(2);
  test.push(3);

  // Stack now looks like:
  console.log(stack.items); // [1, 2, 3]

  // Let's try removing the last element
  stack.pop(); // 3 -> this was the last element we added, so it's the first one that comes out

  // Now the stack looks like this:
  // [1,2]

  // Let's add a new element
  test.push(true);

  // Now the stack looks like:
  // [1,2, true]
  ```

  ## Practical applications

  - Any application that wants to got 'back in time' must utilise a stack. For
    example, the 'undo' function in most software is a function of a stack. The
    most recent action is at the top, and under that is the second most recent and
    so on all the way back to the first action.
  - Recursive functions: a function that calls itself repeatedly until a boundary
    condition is met is using a stack structure. As you drill down through the
    function calls you start from the most recent down to the last.
  - Balancing parentheses. Say you want to check if the following string is
    balanced `[()]` . Every time you find an opening parentheses. You push that to
    the front of a stack. You then compare the closing parentheses with the order
    of the stack. The same could be done when seeking to find palindromes. This
    sort of thing could be a code challenge so build an example.


path: zk/Stale_branches_and_pruning.md
sortable_path: zkStale_branches_and_pruning.md
title: Stale branches and pruning
checksum: d34c069d9cd0bcb5b5771381334d486c897fc97126ae662b213ca3fd8c8dfd30
created: 2024-03-30 09:03:21.194912257+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  A **stale branch** is a
  [remote tracking branch](Remote_tracking_branches.md) that **no
  longer tracks anything** because the actual branch on the remote has been
  deleted.

body:
  A **stale branch** is a
  [remote tracking branch](Remote_tracking_branches.md) that **no
  longer tracks anything** because the actual branch on the remote has been
  deleted.

  If _you_ delete the remote branch, the remote tracking branch will also be
  deleted. However if a _collaborator_ deletes the remote branch, your remote
  tracking branch will remain, becoming a stale branch.

  In order to get rid of it, we need to manually remove it. We can do this with
  the general `prune` command:

  ```sh
  git remote prune origin

  # or run a preview of the action

  git remote prune origin --dry-run
  ```

raw_content:
  ---
  tags: [git]
  ---

  # Stale branches and pruning

  A **stale branch** is a
  [remote tracking branch](Remote_tracking_branches.md) that **no
  longer tracks anything** because the actual branch on the remote has been
  deleted.

  If _you_ delete the remote branch, the remote tracking branch will also be
  deleted. However if a _collaborator_ deletes the remote branch, your remote
  tracking branch will remain, becoming a stale branch.

  In order to get rid of it, we need to manually remove it. We can do this with
  the general `prune` command:

  ```sh
  git remote prune origin

  # or run a preview of the action

  git remote prune origin --dry-run
  ```


path: zk/Step_functions_and_state_machines.md
sortable_path: zkStep_functions_and_state_machines.md
title: AWS Step functions and state machines
checksum: a290427d05b45787caf9f55ac711de8b9361af425c2875ebe09a2fa9ffe38ba2
created: 2024-03-30 09:03:21.203563401+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS"]}
lead:
  _AWS Step Functions_ is an AWS service that allows you to coordinate distributed
  applications and microservices by creating workflows.

body:
  _AWS Step Functions_ is an AWS service that allows you to coordinate distributed
  applications and microservices by creating workflows.

  Workflows are made up of a series of steps and are known as **state machines**.
  A state machine defines:

  - the states of the workflow
  - the transitions between states
  - the inputs and outputs of each state

  State machines are defined via a JSON object which specifies the states and the
  transitions between them. It also includes error catchers and retry logic.

  At the beginning you define a `StartAt` state which is the entrypoint of the
  state machine. This can be manually triggered, or more likely, triggered by
  another AWS service such as a
  [Lambda](Lambda_programming_model.md), an
  [API Gateway](AWS_API_Gateway.md) request or a messaging/queue
  event.

  The state machine ultimately ends at an end state. In between are various
  intermediary states which can include:

  - Task states (do something)
  - Choice states (do something based on conditions)
  - Wait states
  - Success states (if preceding state succeeds do X)
  - Fail states (if preceding state fails do Y)
  - Parallel states

  The diagram below shows the definition of a given state machine. On the left is
  the JSON specification. On the right is a diagramatic representation that shows
  the control flow and all possible steps that comprise a given pathway / state:

  ![](/img/state-machine-definition.png)

  For each execution of the state machine (each time it is triggered) you can
  review the runtime. The flow diagram will highlight green to show the given
  pathway, and you can also see the inputs and outputs for each step and any
  errors:

  ![](/img/state-machine-execution.png)

raw_content:
  ---
  tags: [AWS]
  ---

  # AWS Step functions and state machines

  _AWS Step Functions_ is an AWS service that allows you to coordinate distributed
  applications and microservices by creating workflows.

  Workflows are made up of a series of steps and are known as **state machines**.
  A state machine defines:

  - the states of the workflow
  - the transitions between states
  - the inputs and outputs of each state

  State machines are defined via a JSON object which specifies the states and the
  transitions between them. It also includes error catchers and retry logic.

  At the beginning you define a `StartAt` state which is the entrypoint of the
  state machine. This can be manually triggered, or more likely, triggered by
  another AWS service such as a
  [Lambda](Lambda_programming_model.md), an
  [API Gateway](AWS_API_Gateway.md) request or a messaging/queue
  event.

  The state machine ultimately ends at an end state. In between are various
  intermediary states which can include:

  - Task states (do something)
  - Choice states (do something based on conditions)
  - Wait states
  - Success states (if preceding state succeeds do X)
  - Fail states (if preceding state fails do Y)
  - Parallel states

  The diagram below shows the definition of a given state machine. On the left is
  the JSON specification. On the right is a diagramatic representation that shows
  the control flow and all possible steps that comprise a given pathway / state:

  ![](/img/state-machine-definition.png)

  For each execution of the state machine (each time it is triggered) you can
  review the runtime. The flow diagram will highlight green to show the given
  pathway, and you can also see the inputs and outputs for each step and any
  errors:

  ![](/img/state-machine-execution.png)


path: zk/Stout_stin.md
sortable_path: zkStout_stin.md
title: Standard input and output
lead: https://www.youtube.com/watch?v=kqtD5dpn9C8&ab_channel=ProgrammingwithMosh
body: https://www.youtube.com/watch?v=kqtD5dpn9C8&ab_channel=ProgrammingwithMosh
checksum: a7c555b6f8711caca955958998f44838a9b35428d40f75caf3589f7be5fcd887
created: 2024-03-30 09:03:21.221240268+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-types"]}
raw_content:
  ---
  tags: [python, data-types]
  ---

  # Standard input and output

  https://www.youtube.com/watch?v=kqtD5dpn9C8&ab_channel=ProgrammingwithMosh


path: zk/Strategies_for_constructing_proofs.md
sortable_path: zkStrategies_for_constructing_proofs.md
title: Strategies for constructing proofs in propositional logic
lead: ## General strategy
checksum: d836e2a38a2df56b856a2642dd68e59a49bec4680cf6d9dae8c194f2536358c0
created: 2024-03-30 09:03:21.227368981+00:00
modified: 2024-06-16 16:52:55.36395593+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  ## General strategy

  - Break complex propositions into simpler sentences by using the elimination
    rules
  - Recombine simple propositions into complex propositions using the introduction
    rules.

  ## Goal analysis

  The approach above describes the general form of a proof but of course it will
  not always work and there will be cases where the route to the desired
  derivation is more circuitous. In these instances it is to best to combine this
  general top level strategy with goal analysis.

  Goal analysis is a [recursive](Recursion.md) strategy which
  proceeds by using a 'goal' proposition to guide the construction of intermediary
  derivations.

  Assume that we want to show that an argument is
  [valid](Validity_and_entailment.md#validity). Then our
  ultimate goal is to derive the conclusion from the premises we are given. We
  first ask ourselves: _which propositions if we could derive them, would allow us
  to easily derive the conclusion_? (For example, these propositions might be two
  simple propositions that when combined with
  [Conjunction Introduction](Conjunction_Introduction.md) give us
  the conclusion.) Deriving these propositions then becomes the new intermediate
  goal.

  If arriving at these propositions is not trivial, we then ask ourselves the
  question again: _which propositions would permit us to derive the intermediary
  propositions we need_? You keep working back in this manner until you reach a
  base level. Then it is just a matter or working upwards from each set of derived
  intermediary propositions until you reach the ultimate goal.

  ### Demonstration

  Let's say we want to prove $(L \lor A) \land D$ from the propositions $\lnot N$
  and $((\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N))$.

  First, we consider what is the easiest possible way of achieving the proposition
  $(L \lor A) \land D$. Clearly it is to separately derive each disjunct
  ($L \lor A$ and $D$) and then combine them with
  [Conjunction Introduction](Conditional_Introduction.md). This
  provides us with our first goal: to derive each of the separate conjuncts.

  Let's start with $D$: where does it occur in the assumptions? It occurs in the
  compound $(\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N)$, but only
  in the first conjunct. We can get this simply but applying
  [Conjunction Elimination](Conjunction%20Elimination.md).

  So far we have:

  ![](/img/step1.png)

  Now we just need to get $D$ from the proposition at line 3. This is easy since
  we already have access to the consequent of the biconditional at line 1.
  Therefore we can apply
  [Biconditional Elimination](Biconditional_Elimination.md)) at line
  3 to get $D$. We are now halfway there:

  ![](/img/step2.png)

  Next we need to turn our attention to deriving $L \lor A$. How can we obtain $L$
  ? Well it is contained within the first conjunct of the assumption on line 2.
  Again, we can get this through the application of
  [Conjunction Elimination](Conjunction_Elimination.md). Now, how do
  we get $L$ from $(\lnot N \rightarrow L)$? Well, we already have the antecedent
  $\lnot N$ as an assumption on the first line, so we can use
  [Conditional Elimination](Conditional_Elimination.md) to derive
  $L$. These two steps give us:

  ![](/img/step3.png)

  Now we need to get from $L$ to $L \lor A$. This is really straightforward
  because by using
  [Disjunction Introduction](Disjunction_Introduction.md)) we can
  get from any sentence to a disjunction. Finally, having assembled all the
  constituent parts of the conjunction that is the conclusion, we can combine them
  with [Conjunction Introduction](Conjunction_Introduction.md) as we
  had planned at the outset.

  ![](/img/step4.png)

  ### A further example

  We will seek to prove the following:

  $$
  \{ \lnot L \leftrightarrow [X \land (\lnot S \lor B) ], (E \land C) \rightarrow \lnot L, (E \land R) \land C \} \vdash X \land (\lnot S \lor B)
  $$

  The requirements here could easily mislead us. We see that the target
  proposition is a conjunction so we might think that the best strategy is to seek
  to derive each conjunct and then combine them via
  [Conjunction Introduction](Conjunction_Introduction.md)).

  Actually, if we look more closely, there is a better approach. The target
  proposition is contained in the first premise as the consequent to the
  biconditional ($\lnot L \leftrightarrow [X \land (\lnot S \lor B)]$). A better
  approach is therefore to seek to derive the antecedent ($\lnot L$) and then use
  [Biconditional Elimination](Biconditional_Elimination.md) to
  extract the target sentence which is the consequent.

  ![proof.png](proof.png)

  ## Proving theorems

  When we are proving
  [theorems](Theorems_and_empty_sets.md#theorems-and-empty-sets)
  we do not have a set of assumptions to work from when constructing the proof. We
  must derive the target sentence from the 'empty set' which is the target
  sentence itself. It is therefore like a process of reverse engineering.

  ### Demonstration

  _Prove:_ $\vdash (U \land Y) \rightarrow [L \rightarrow (U \land L)]$

  Our strategy here is to identify the main connective in the proposition we want
  to derive (the material conditional). We then assume the antecedent and attempt
  to derive the consequent from it.

  ![](/img/theoremproof.png)

  ## A complex theorem proof

  _Prove_ $\vdash (\lnot A \lor \lnot B) \leftrightarrow \lnot(A \land B)$

  ![](/img/dsfdsfsdfwe.png)

  ### Walkthrough

  **Lines 1-12**

  - Our auxiliary goal is to prove
    $\lnot (A \lor B) \rightarrow \lnot (A \land B)$.

  - Our starting assumption is to a disjunction. Thus we can apply
    [Disjunction Elimination](Disjunction_Elimination.md) to show
    that our goal sentence $\lnot(A \land B)$ follows from each of the disjuncts
    ($\lnot A$ and $\lnot B$) in dedicated sub-proofs. If we can do this, we have
    the right to derive $\lnot (A \land B)$.

  - In both cases($\lnot A \vdash \lnot (A \land B)$) and
    ($\lnot B \vdash \lnot (A \land B)$ we require another sub-proof to reach the
    target as there is no easy path available. So we derive a negation from
    $A \land  B$ so that we can negate it as $\lnot (A \land B)$.

  - Having done this, we can discharge the
    [Disjunction Elimination](Disjunction_Elimination.md) sub-proofs
    and derive $\lnot (A \land B)$ from $\lnot A \lor \lnot B$

  **Lines 13-26**

  - Our auxiliary goal is to prove
    $\lnot (A \land B) \rightarrow \lnot A \lor  \lnot B$. This will require a
    different approach to the above because we are not working from a disjunction
    anymore, we have a negated conjunction.
  - We will do this by assuming the negation of what we want to prove
    ($\lnot (\lnot A \lor \lnot B)$) and then apply
    [Negation Elimination](Negation_Elimination.md) to get
    $\lnot A \lor \lnot B$.
  - This requires us to derive a contradiction. We get this on lines 23 and 24.
    This requires as previous steps that we have two sub-proofs that use
    [Negation Elimination](Negation_Elimination.md) to release $A$
    and $B$

raw_content:
  ---
  tags:
    - propositional-logic
    - logic
  ---

  # Strategies for constructing proofs in propositional logic

  ## General strategy

  - Break complex propositions into simpler sentences by using the elimination
    rules
  - Recombine simple propositions into complex propositions using the introduction
    rules.

  ## Goal analysis

  The approach above describes the general form of a proof but of course it will
  not always work and there will be cases where the route to the desired
  derivation is more circuitous. In these instances it is to best to combine this
  general top level strategy with goal analysis.

  Goal analysis is a [recursive](Recursion.md) strategy which
  proceeds by using a 'goal' proposition to guide the construction of intermediary
  derivations.

  Assume that we want to show that an argument is
  [valid](Validity_and_entailment.md#validity). Then our
  ultimate goal is to derive the conclusion from the premises we are given. We
  first ask ourselves: _which propositions if we could derive them, would allow us
  to easily derive the conclusion_? (For example, these propositions might be two
  simple propositions that when combined with
  [Conjunction Introduction](Conjunction_Introduction.md) give us
  the conclusion.) Deriving these propositions then becomes the new intermediate
  goal.

  If arriving at these propositions is not trivial, we then ask ourselves the
  question again: _which propositions would permit us to derive the intermediary
  propositions we need_? You keep working back in this manner until you reach a
  base level. Then it is just a matter or working upwards from each set of derived
  intermediary propositions until you reach the ultimate goal.

  ### Demonstration

  Let's say we want to prove $(L \lor A) \land D$ from the propositions $\lnot N$
  and $((\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N))$.

  First, we consider what is the easiest possible way of achieving the proposition
  $(L \lor A) \land D$. Clearly it is to separately derive each disjunct
  ($L \lor A$ and $D$) and then combine them with
  [Conjunction Introduction](Conditional_Introduction.md). This
  provides us with our first goal: to derive each of the separate conjuncts.

  Let's start with $D$: where does it occur in the assumptions? It occurs in the
  compound $(\lnot N \rightarrow L) \land (D \leftrightarrow \lnot N)$, but only
  in the first conjunct. We can get this simply but applying
  [Conjunction Elimination](Conjunction%20Elimination.md).

  So far we have:

  ![](/img/step1.png)

  Now we just need to get $D$ from the proposition at line 3. This is easy since
  we already have access to the consequent of the biconditional at line 1.
  Therefore we can apply
  [Biconditional Elimination](Biconditional_Elimination.md)) at line
  3 to get $D$. We are now halfway there:

  ![](/img/step2.png)

  Next we need to turn our attention to deriving $L \lor A$. How can we obtain $L$
  ? Well it is contained within the first conjunct of the assumption on line 2.
  Again, we can get this through the application of
  [Conjunction Elimination](Conjunction_Elimination.md). Now, how do
  we get $L$ from $(\lnot N \rightarrow L)$? Well, we already have the antecedent
  $\lnot N$ as an assumption on the first line, so we can use
  [Conditional Elimination](Conditional_Elimination.md) to derive
  $L$. These two steps give us:

  ![](/img/step3.png)

  Now we need to get from $L$ to $L \lor A$. This is really straightforward
  because by using
  [Disjunction Introduction](Disjunction_Introduction.md)) we can
  get from any sentence to a disjunction. Finally, having assembled all the
  constituent parts of the conjunction that is the conclusion, we can combine them
  with [Conjunction Introduction](Conjunction_Introduction.md) as we
  had planned at the outset.

  ![](/img/step4.png)

  ### A further example

  We will seek to prove the following:

  $$
  \{ \lnot L \leftrightarrow [X \land (\lnot S \lor B) ], (E \land C) \rightarrow \lnot L, (E \land R) \land C \} \vdash X \land (\lnot S \lor B)
  $$

  The requirements here could easily mislead us. We see that the target
  proposition is a conjunction so we might think that the best strategy is to seek
  to derive each conjunct and then combine them via
  [Conjunction Introduction](Conjunction_Introduction.md)).

  Actually, if we look more closely, there is a better approach. The target
  proposition is contained in the first premise as the consequent to the
  biconditional ($\lnot L \leftrightarrow [X \land (\lnot S \lor B)]$). A better
  approach is therefore to seek to derive the antecedent ($\lnot L$) and then use
  [Biconditional Elimination](Biconditional_Elimination.md) to
  extract the target sentence which is the consequent.

  ![proof.png](proof.png)

  ## Proving theorems

  When we are proving
  [theorems](Theorems_and_empty_sets.md#theorems-and-empty-sets)
  we do not have a set of assumptions to work from when constructing the proof. We
  must derive the target sentence from the 'empty set' which is the target
  sentence itself. It is therefore like a process of reverse engineering.

  ### Demonstration

  _Prove:_ $\vdash (U \land Y) \rightarrow [L \rightarrow (U \land L)]$

  Our strategy here is to identify the main connective in the proposition we want
  to derive (the material conditional). We then assume the antecedent and attempt
  to derive the consequent from it.

  ![](/img/theoremproof.png)

  ## A complex theorem proof

  _Prove_ $\vdash (\lnot A \lor \lnot B) \leftrightarrow \lnot(A \land B)$

  ![](/img/dsfdsfsdfwe.png)

  ### Walkthrough

  **Lines 1-12**

  - Our auxiliary goal is to prove
    $\lnot (A \lor B) \rightarrow \lnot (A \land B)$.

  - Our starting assumption is to a disjunction. Thus we can apply
    [Disjunction Elimination](Disjunction_Elimination.md) to show
    that our goal sentence $\lnot(A \land B)$ follows from each of the disjuncts
    ($\lnot A$ and $\lnot B$) in dedicated sub-proofs. If we can do this, we have
    the right to derive $\lnot (A \land B)$.

  - In both cases($\lnot A \vdash \lnot (A \land B)$) and
    ($\lnot B \vdash \lnot (A \land B)$ we require another sub-proof to reach the
    target as there is no easy path available. So we derive a negation from
    $A \land  B$ so that we can negate it as $\lnot (A \land B)$.

  - Having done this, we can discharge the
    [Disjunction Elimination](Disjunction_Elimination.md) sub-proofs
    and derive $\lnot (A \land B)$ from $\lnot A \lor \lnot B$

  **Lines 13-26**

  - Our auxiliary goal is to prove
    $\lnot (A \land B) \rightarrow \lnot A \lor  \lnot B$. This will require a
    different approach to the above because we are not working from a disjunction
    anymore, we have a negated conjunction.
  - We will do this by assuming the negation of what we want to prove
    ($\lnot (\lnot A \lor \lnot B)$) and then apply
    [Negation Elimination](Negation_Elimination.md) to get
    $\lnot A \lor \lnot B$.
  - This requires us to derive a contradiction. We get this on lines 23 and 24.
    This requires as previous steps that we have two sub-proofs that use
    [Negation Elimination](Negation_Elimination.md) to release $A$
    and $B$


path: zk/Streams.md
sortable_path: zkStreams.md
title: Handling streams with fs
checksum: f8299b5e6a1242c1e024952c4e37aaa85dbc54a9b22f1a262b3658605e2ec655
created: 2024-03-30 09:03:21.314381203+00:00
modified: 2024-06-15 09:50:45.043601129+00:00
metadata: {"tags":["node-js"]}
lead:
  When reading from a file, the
  [`fs.readFile()`](fs.md) method waits
  until the entire file has been read before executing the callback. It's obvious
  why this might not be ideal in certain cases. If the file is very large you are
  utilising a lot of [memory](Memory.md) for a
  single process. Additionally, the data you need might appear early in the file,
  in which case, once you find the data you want, there is no need to read to the
  end of the file.

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

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

  ## Reading streams

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

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

  ## Implementation

  Instead of, e.g :

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

  We would:

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

  let data;

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

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

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

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

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

  ## Writing streams

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

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

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

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

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

  Note that we always have to close the stream on exit

raw_content:
  ---
  tags:
    - node-js
  ---

  # Handling streams with fs

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

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

  ## Reading streams

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

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

  ## Implementation

  Instead of, e.g :

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

  We would:

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

  let data;

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

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

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

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

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

  ## Writing streams

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

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

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

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

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

  Note that we always have to close the stream on exit


path: zk/Strings_in_Python.md
sortable_path: zkStrings_in_Python.md
title: Strings in Python
checksum: 3281a0dcc11d012d63621b70be662326f2a19865f9e34b84f32e7679bff270a7
created: 2024-03-30 09:03:21.329698316+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-types"]}
lead:
  > 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

body:
  > 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']
  ```

raw_content:
  ---
  tags: [python, data-types]
  ---

  # 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']
  ```


path: zk/Strings_in_bash.md
sortable_path: zkStrings_in_bash.md
title: Strings in bash
lead: ## Return a substring by index
checksum: 2530f2db53c8899fd0d79f4d754052143e4479eb4e64620e2cc4cc233aca8321
created: 2024-03-30 09:03:21.338894905+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell","data-types"]}
body:
  ## Return a substring by index

  ```bash
  myString="hello"
  substring=${myString:0:3}
  # hel
  ```

  This is often used when looping through each character in a string.

  ## Loop through each character in a string

  ```bash
  str="hallelujah"
  stringLength=$(expr length str)

  for (( i=0; i<=${stringLength}; i++ )); do
      echo "${str:$i:1}"
  done
  ```

raw_content:
  ---
  tags:
    - shell
    - data-types
  ---

  # Strings in bash

  ## Return a substring by index

  ```bash
  myString="hello"
  substring=${myString:0:3}
  # hel
  ```

  This is often used when looping through each character in a string.

  ## Loop through each character in a string

  ```bash
  str="hallelujah"
  stringLength=$(expr length str)

  for (( i=0; i<=${stringLength}; i++ )); do
      echo "${str:$i:1}"
  done
  ```


path: zk/Structuring_Express_applications.md
sortable_path: zkStructuring_Express_applications.md
title: Structuring Express applications
lead: In general, the following application structure works well:
checksum: 7a70ba15689a6e7e95f95149fa25048890b62d3003d249060f54bf4a76b99b6d
created: 2024-03-30 09:03:21.345088468+00:00
modified: 2024-06-15 10:04:27.272112458+00:00
metadata: {"tags":["node-js","REST","APIs"]}
body:
  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.

raw_content:
  ---
  tags:
    - node-js
    - REST
    - APIs
  ---

  # 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.


path: zk/Swap_space.md
sortable_path: zkSwap_space.md
title: Swap space
checksum: 0af508235e21dfd0c4513a5191c87db4d1dea95737814ea9311f895ad026f5f0
created: 2024-03-30 09:03:21.353806715+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["memory","disks"]}
lead:
  A swap partition is a partition on a disk that is not intended to be used as a
  filesystem. Instead, it is a part of the disk that is used to augment the main
  memory.

body:
  A swap partition is a partition on a disk that is not intended to be used as a
  filesystem. Instead, it is a part of the disk that is used to augment the main
  memory.

  If you run out of memory and have set up a swap partition, the OS will be able
  to move pieces of memory to and from disk storage. This is called _swapping_
  because pieces of idle programs are swapped to the disk in exchange for active
  pieces residing on the disk.

  ## View current swap usage

  If you have a swap space established, the command `free` will show current
  usage:

  ```bash
  free
                 total        used        free      shared  buff/cache   available
  Mem:        16099420     3031572    10157652     1153144     2910196    11605820
  Swap:        3145724           0     3145724
  ```

  ## Create a swap partition

  To use an existing disk partition as a swap you can run the command
  `mkswap [device]` and then `swapon [device]` to register the space with the
  [kernel](The_Kernel.md).

  ### Add to `fstab`

  You will want the swap to be activated every time the OS boots so add the
  following line to the [fstab](Filesystems.md#fstab),
  where `/sda3` is used as the example partition:

  ```bash
  /dev/sda3e none swap sw 0 0
  ```

  ## Create a swap file

  // Add info here

raw_content:
  ---
  tags:
    - memory
    - disks
  ---

  # Swap space

  A swap partition is a partition on a disk that is not intended to be used as a
  filesystem. Instead, it is a part of the disk that is used to augment the main
  memory.

  If you run out of memory and have set up a swap partition, the OS will be able
  to move pieces of memory to and from disk storage. This is called _swapping_
  because pieces of idle programs are swapped to the disk in exchange for active
  pieces residing on the disk.

  ## View current swap usage

  If you have a swap space established, the command `free` will show current
  usage:

  ```bash
  free
                 total        used        free      shared  buff/cache   available
  Mem:        16099420     3031572    10157652     1153144     2910196    11605820
  Swap:        3145724           0     3145724
  ```

  ## Create a swap partition

  To use an existing disk partition as a swap you can run the command
  `mkswap [device]` and then `swapon [device]` to register the space with the
  [kernel](The_Kernel.md).

  ### Add to `fstab`

  You will want the swap to be activated every time the OS boots so add the
  following line to the [fstab](Filesystems.md#fstab),
  where `/sda3` is used as the example partition:

  ```bash
  /dev/sda3e none swap sw 0 0
  ```

  ## Create a swap file

  // Add info here


path: zk/Syllogism.md
sortable_path: zkSyllogism.md
title: Syllogism
checksum: efa3d071823652b3ce7959d58ea9a4b400250d7f5cb9fe963479e825295704cd
created: 2024-03-30 09:03:21.374253335+00:00
modified: 2024-06-16 16:53:00.363726303+00:00
metadata: {"tags":["propositional-logic","logic"]}
lead:
  In order to make assertions about the relative
  [consistency](Logical_consistency.md) or inconsistency
  of a set of propositions we advance arguments. Consider everyday life: if we are
  having an argument with someone, we believe that they are wrong. A more logical
  way to say this is that we believe that their beliefs are inconsistent. In order
  to change their viewpoint or point out why they are wrong we advance an argument
  intended to show that belief A conflicts with belief B. Or if C is true, then
  you cannot believe that D.

body:
  In order to make assertions about the relative
  [consistency](Logical_consistency.md) or inconsistency
  of a set of propositions we advance arguments. Consider everyday life: if we are
  having an argument with someone, we believe that they are wrong. A more logical
  way to say this is that we believe that their beliefs are inconsistent. In order
  to change their viewpoint or point out why they are wrong we advance an argument
  intended to show that belief A conflicts with belief B. Or if C is true, then
  you cannot believe that D.

  In formal terms **an argument is a set of propositions comprising one or more
  premises and a conclusion. The conclusion is taken to be supported by the
  premises.**

  > The terms **argument** and **syllogism** are used interchangeably in logic to
  > describe the above feature of a set of propositions.

  ### Demonstration

  ```
  (P1) All men are mortal.
  (P2) Socrates is a man.
  _____________________
  (C) Socrates is mortal
  ```

raw_content:
  ---
  tags:
    - propositional-logic
    - logic
  ---

  # Syllogism

  In order to make assertions about the relative
  [consistency](Logical_consistency.md) or inconsistency
  of a set of propositions we advance arguments. Consider everyday life: if we are
  having an argument with someone, we believe that they are wrong. A more logical
  way to say this is that we believe that their beliefs are inconsistent. In order
  to change their viewpoint or point out why they are wrong we advance an argument
  intended to show that belief A conflicts with belief B. Or if C is true, then
  you cannot believe that D.

  In formal terms **an argument is a set of propositions comprising one or more
  premises and a conclusion. The conclusion is taken to be supported by the
  premises.**

  > The terms **argument** and **syllogism** are used interchangeably in logic to
  > describe the above feature of a set of propositions.

  ### Demonstration

  ```
  (P1) All men are mortal.
  (P2) Socrates is a man.
  _____________________
  (C) Socrates is mortal
  ```


path: zk/Symlinks.md
sortable_path: zkSymlinks.md
title: Syntax
lead:
  ```
  ln -s -f ~/[existing_file] ~/.[file_you_want_to_symbolise]
  ```

checksum: 0c0d42f0333ae4a9f7556b6e1262deb9e631ee22a79656087f1424358cd9c9d4
created: 2024-03-30 09:03:21.384507293+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ```
  ln -s -f ~/[existing_file] ~/.[file_you_want_to_symbolise]
  ```

  Real example:

  ```
  ln -s -f ~/dotfiles/.vimrc ~/.vimrc
  ```

raw_content:
  ---
  tags:
    - shell
  ---

  > A symbolic link, also termed a soft link, is a special kind of file that
  > points to another file. Unlike a hard link, a symbolic link does not contain
  > the data in the target file. It simply points to another entry somewhere in
  > the file system.

  # Syntax

  ```
  ln -s -f ~/[existing_file] ~/.[file_you_want_to_symbolise]
  ```

  Real example:

  ```
  ln -s -f ~/dotfiles/.vimrc ~/.vimrc
  ```


path: zk/Syntax_of_propositional_logic.md
sortable_path: zkSyntax_of_propositional_logic.md
title: Syntax of propositional logic
lead: ## Syntax of formal languages versus semantics
checksum: 62edccda4593be282121ee3b522e1dc1bd9a989fa7475c32470c54ea34730039
created: 2024-03-30 09:03:21.390639601+00:00
modified: 2024-06-16 16:53:05.633494193+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  ## 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$.

raw_content:
  ---
  tags:
    - propositional-logic
    - logic
  ---

  # 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$.


path: zk/Tags_in_Git.md
sortable_path: zkTags_in_Git.md
title: Tags in Git
checksum: b684f8ef44eb962d1c0262ba8934999fc798aa1d14d52b9dacc2cb0b680da031
created: 2024-03-30 09:03:21.399470534+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  Tags exist to reference specific commits in a more meaningful way than using a
  SHA reference. They are a **named reference to a commit**. As they refer to a
  singular commit they do not update but are a fixed point in the Git history.

body:
  Tags exist to reference specific commits in a more meaningful way than using a
  SHA reference. They are a **named reference to a commit**. As they refer to a
  singular commit they do not update but are a fixed point in the Git history.

  > Tags do not care about branches. They are an objective reference to a commit
  > regardless of which branch it occured on. You can reference a tag without
  > needing to be in the branch where the tagging originally took place.

  Tags are frequently used to mark software release versions. But they can also be
  used for other designations such as the addition of a key feature or bug.

  ## Creating a tag

  ```
  git tag -am "Version 1.0" v1.0 dd5c4539a0
  ```

  `am` is for "annotated + message". The actual tag name is `v1.0`

  Now you can refer to that commit with `v1.0` rather than use the SHA

  ## Deleting a tag

  ```
  git tag -d v1.0
  ```

  > When you delete the tag you are only deleting the tag reference not the commit
  > that it refers to.

  ## Listing tags

  ```
  git tag --list
  ```

  ## Examples of use

  ```
  git show v1.1

  git diff v1.0..v1.1
  ```

  ## Pushing tags to a remote

  In the examples so far, all the tags have been **local tags**. They only exist
  in our local workflow and are not accessible to our collaborators. If we do a
  `git push`, this doesn't transfer our local tags. You have to do:

  ```
  git push origin [tag-name]
  ```

  Push all tags:

  ```
  git push origin --tags

  # Delete remote tag

  git push -d origin [tag-name]
  ```

  ## Getting tags from the remote

  ```
  git fetch
  ```

  This automatically fetches tags too.

raw_content:
  ---
  tags: [git]
  ---

  # Tags in Git

  Tags exist to reference specific commits in a more meaningful way than using a
  SHA reference. They are a **named reference to a commit**. As they refer to a
  singular commit they do not update but are a fixed point in the Git history.

  > Tags do not care about branches. They are an objective reference to a commit
  > regardless of which branch it occured on. You can reference a tag without
  > needing to be in the branch where the tagging originally took place.

  Tags are frequently used to mark software release versions. But they can also be
  used for other designations such as the addition of a key feature or bug.

  ## Creating a tag

  ```
  git tag -am "Version 1.0" v1.0 dd5c4539a0
  ```

  `am` is for "annotated + message". The actual tag name is `v1.0`

  Now you can refer to that commit with `v1.0` rather than use the SHA

  ## Deleting a tag

  ```
  git tag -d v1.0
  ```

  > When you delete the tag you are only deleting the tag reference not the commit
  > that it refers to.

  ## Listing tags

  ```
  git tag --list
  ```

  ## Examples of use

  ```
  git show v1.1

  git diff v1.0..v1.1
  ```

  ## Pushing tags to a remote

  In the examples so far, all the tags have been **local tags**. They only exist
  in our local workflow and are not accessible to our collaborators. If we do a
  `git push`, this doesn't transfer our local tags. You have to do:

  ```
  git push origin [tag-name]
  ```

  Push all tags:

  ```
  git push origin --tags

  # Delete remote tag

  git push -d origin [tag-name]
  ```

  ## Getting tags from the remote

  ```
  git fetch
  ```

  This automatically fetches tags too.


path: zk/Test_values_in_Bash.md
sortable_path: zkTest_values_in_Bash.md
title: Test values in Bash
checksum: ba86d2213153c9b931badff1f8196705a5c4585e7434829944ef3b091495d1cd
created: 2024-03-30 09:03:21.406143623+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell","regex"]}
lead:
  `test` is a built-in command that is used to compare values or determine whether
  something is the case.

body:
  `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.md).

raw_content:
  ---
  tags:
    - shell
    - regex
  ---

  # 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.md).


path: zk/Testing_Python_code.md
sortable_path: zkTesting_Python_code.md
title: Testing Python code
lead: ## `pytest`
checksum: f21ee764b3d4c67afa18fdc25fbee482906dd1434c85f34660de4f8726cbaeab
created: 2024-03-30 09:03:21.415795229+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","testing"]}
body:
  ## `pytest`

  Pytest is the most popular testing library for Python. It is not included with
  the Python standard library so it must be installed with
  [pip](Python_package_management.md).
  While it does not include a declaration library, it is robust enough to handle
  most scenarios having a rich and expressive set of constructs and decorators
  that let you declare what your tests should do, under what conditions they
  should run, and how they should interact with the rest of your system.

  ### Using `pytest`

  - Pytest will automatically detect test files so long as they are named
    appropriately. E.g. for a module called `lorem`, it will detzect the unit test
    files `lorem_test.py` and `test_lorem.py`.
  - In order to detect tests it should be run from a directory level above them

  ### Examples

  Here is a basic example of using pytest for a local module callled `palindrome`:

  ```py
  import palindrome

  def test_is_palindrome():
      assert palindrome.is_palindrome('soros')
      assert palindrome.is_palindrome('torot')
      assert not palindrome.is_palindrome('chair')
  ```

  ## Mocking

  `patch()` and `Mock` enable us to mock objects whilst testing (classes,
  functions, methods and properties belonging). They are used in combination.

  The `@patch` decorator temporarily replaces a specified object in your code with
  a mock object and restores the original object after the test is complete

  A Mock object simulates the object it replaces so that the object behaves as
  expected during testing. For example, if your code calls
  `some_function.some_method()`, and `some_method` is mocked, calling
  `some_method` will not execute real logic but will interact with the Mock object
  instead. Mock objects record details about how they have been used, like what
  methods have been called, with what arguments, etc., allowing you to make
  assertions about how they have been used.

  > `@patch` and `Mock` work together because a patch is used to replace an object
  > or attribute with a Mock object. `Mock` handles the simulated functionality,
  > and `@patch` designates the real value we are replacing with the mock.

  ### Example case

  I will use the following example from one my projects:

  ```py
  # get_articles.py
  def get_articles(article_type: str) -> Optional[Dict[str, Any]]:
      """Retrieve articles from Pocket API"""

      if POCKET_LAMBDA_ENDPOINT is None:
          logging.error("Error: POCKET_LAMBDA_ENDPOINT envinronment variable is not set")
          return None
      else:
          # Interpolate the article_type into the Pocket request URL
          endpoint = POCKET_LAMBDA_ENDPOINT.format(article_type=article_type)

      try:
          response = requests.get(endpoint)
          response.raise_for_status()
          return response.json()

      except RequestException as e:
          print(f"An error occurred: {e}")
          return None
  ```

  This function: sources a URL from an environment variable, interpolates a query
  string into the URL (which comes in as a parameter), makes a request to the URL,
  and returns the response as JSON.

  It has some safeguards in place:

  - It checks that the environment variable is set
  - It checks that the request was successful

  In the example we could use a Mock object to simulate the response from the
  Pocket API. This would allow us to test the function without having to make a
  real request to the API:

  ```py
  def test_successful_request():
      # Replace the requests.get function with a Mock object (mock_get)
      with patch("requests.get") as mock_get:
          # Specify the return value of the mock_get object)
          mock_get.return_value = Mock(ok=true)
          mock_get.return_value.json.return_value = {"value": "test"}

          # Call the function under test
          result = get_articles("gaby")

      # Assert expected outcomes
      mock_get.assert_called_once_with(endpoint)
      assert result == mock_json_response
  ```

  The example above follows the **Arrange, Act, Assert** pattern:

  | Stage   | Action                                                                          |
  | ------- | ------------------------------------------------------------------------------- |
  | Arrange | Replace the `requests.get` function with `patch` and set properties with `Mock` |
  | Act     | Call the function under test                                                    |
  | Assert  | Assert that the function under test behaved as expected                         |

  ### Alternative mock syntax

  The `with patch(...) as mock_name` syntax is fine for small-scale mocking but
  can become cumbersome when you are mocking several dependencies.

  There is another syntax (which I actually find clearer). Say we have a function
  with three dependencies: `update_worksheet`, `process_articles`, `get_articles`.
  We could mock like so:

  ```py
  @patch("app.update_worksheet")
  @patch("app.process_articles")
  @patch("app.get_articles")
  def test_success(
      mock_get_articles, mock_process_articles, mock_update_worksheet
  ):
      mock_get_articles.return_value = [1, 2, 3]
  ```

  Here the patching is done by the decorator and the mocks are defined as
  parameters to the test function (always in reverse order)

  ### Mock assertion lexicon

  #### `return_value`

  State what the mock should return

  ```py
  my_mocked_function.return_value = ['one', 'two', 'three']
  ```

  #### `call_count`

  Test how many times a dependent function is called

  ```py
  assert my_mocked_function.call_count = 3
  ```

  #### `assert_any_call()`

  Test that a given mock is called at least once during the execution of the
  function under test

  ```py
  my_mocked_function.assert_any_call(some_mocked_return_value)
  ```

  When the output of one function is used as a parameter to another, and we don't
  particularly care about the details of what is concerned we can just pass the
  executed function, e.g:

  ```py
  my_mocked_function.assert_any_call(preceding_function())
  ```

  #### `call_args_list`

  Get a list of all the arguments that a mock object was called with during the
  test.

  `call_args_list` is useful when you want to check the arguments that a mock
  object was called with during the test, especially if the mock object was called
  multiple times with different arguments. You can use it to inspect the arguments
  of each call and make assertions based on them.

  ```py
  second_my_mocked_function_call = my_mocked_function.call_args_list[1]

  # check the first argument of the second call:

  assert second_my_mocked_function_call[0][0] == "expected arg"
  ```

  #### `side_effect`

  Use to trigger a side effect when returning a value from a mock. Most useful for
  mocking exceptions.

  ```py
  my_mocked_function.side_effect = Exception("Some exception raised")
  ```

  ## Testing exceptions with `raises`

  Testing exceptions is quite straightforward. You can use the `raises` helper
  provided by pytest, and combine this with `excinfo` ("exception info") to
  inspect the exception message.

  ```py
  if POCKET_LAMBDA_ENDPOINT is None:
      raise ValueError(
          "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set"
      )
  ```

  Then to test this, we would use pytest's `excinfo` fixture along with `raises`:

  ```py
   with pytest.raises(ValueError) as excinfo:  # Watch for the ValueError
      get_articles("some_type")

      assert "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set" in str(
          excinfo.value
      )
  ```

  We could actually simplify the above test by using the `match` parameter with
  `raise`. This way we do not need the separate assertion:

  ```py
  with pytest.raises(ValueError, match="Error: POCKET_LAMBDA_ENDPOINT environment variable is not set"):
      get_articles("some_type")
  ```

  Note that `excinfo` is best used for testing the exception text that you the
  developer explicitly `raise`. For exceptions tha may occur naturaly in the code
  you are testing, you should use `caplog` or `capsys` (see below).

  ## Before-each and after-each

  When testing functions, we achieve this in Python using `setup_function` and
  `teardown_function` methods. These methods are called before and after each test
  method respectively.

  To apply a "before each" to _every test_ just put your setup function and/or
  teardown function at the top level of your test module.

  For example, below we set and remove an env var before and after each test:

  ```py
  @pytest.fixture(scope="function") # specify that this fixture should be run before each function test
  def setup_function():
      print("Setting up test environment...")
      os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"


  def teardown_function():
      print("Tearing down test environment...")
      del os.environ["POCKET_LAMBDA_ENDPOINT"]
  ```

  If the setup/teardown should only be applied to a subset of tests, just pass the
  name of the fixture as a parameter to the test function:

  ```py
  def some_function(setup_function):
      # setup_function will be run before this test
  ```

  You don't need to use the names `setup_function` and `teardown_function` so long
  as you are passing the fixture as a parameter.

  You can also use `yield` to combine the setup and teardown into a single
  function:

  ```py
  @pytest.fixture(scope="function")
  def setup_function():
      os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"
      yield
      del os.environ["POCKET_LAMBDA_ENDPOINT"]
  ```

  ### Another example:

  The following test suite uses the same three mocked functions in every test. The
  following set-up assigns the mocks before each test and resets after each
  individual test has run:

  ```py
  @pytest.fixture(scope="function")
  def setup_function():
      with patch("app.get_articles") as mock_get_articles, patch(
          "app.process_articles"
      ) as mock_process_articles, patch("app.update_worksheet") as mock_update_worksheet:
          yield mock_get_articles, mock_process_articles, mock_update_worksheet
  ```

  Then to use:

  ```py
  def individual_test(setup_function):
      mock_get_articles, mock_process_articles, mock_update_worksheet = setup_function
      # Now each mock can be referenced using the vars above

  ```

  ## Parameterized tests

  For a sequence of tests that are repetitive, to avoid repeating the same code
  over and over again, we can use parameterized tests. This is where we pass in a
  list of parameters to the test function and the test function is run once for
  each parameter.

  For example, in the function below I am handling numerous possible Exceptions
  that could be raised by the `requests.get` method:

  ```py
      try:
          response = requests.get(endpoint)
          response.raise_for_status()
          return response.json()

      except HTTPError as http_err:
          logging.error(f"HTTP Error occurred: {http_err}")

      except ConnectionError as conn_err:
          logging.error(f"Connection Error occurred: {conn_err}")

      except Timeout as timeout_err:
          logging.error(f"Timeout Error occurred: {timeout_err}")

      except RequestException as e:
          logging.error(f"Request Exception occurred: {e}")

      return None
  ```

  Instead of writing something like the following for each of the four exceptions:

  ```py

   def test_exception_generic(caplog):
      with patch("requests.get", side_effect=RequestException("Some error")):
          result = get_articles("some_type")

      assert "Request Exception occurred" in caplog.text
      assert result is None
  ```

  I could parameterize like so:

  ```py
  @pytest.mark.parametrize(
      "exception_type, log_message",
      [
          (RequestException, "Request Exception occurred: "),
          (HTTPError, "HTTP Error occurred: "),
          (Timeout, "Timeout Error occurred: "),
          (ConnectionError, "Connection Error occurred: "),
      ],
  )
  def test_exceptions(caplog, exception_type, log_message):
      with patch("requests.get", side_effect=exception_type("Some error")):
          result = get_articles("some_type")

      assert log_message in caplog.text
      assert result is None
  ```

  ## Caplog, syslog, excinfo

  `caplog` and `capsys` are built-in pytest fixtures. `caplog` lets you test log
  messages. `capsys` lets you test stdout and stderr. As such they are very useful
  when testing that error messages are logged correctly.

  ### `caplog`

  In our example, if the endpoing environment is not set, we log an error message.
  We can test that this message is logged correctly using `caplog`:

  ```py
  def test_no_endpoint_env_var(caplog):
      os.environ.pop("POCKET_LAMBDA_ENDPOINT", None)  # Remove env variable if it exists

      with caplog.at_level(logging.ERROR):
          result = get_articles("some_type")

      assert (
          "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set" in caplog.text
      )
      assert result is None
  ```

  > Note tha we pass in `caplog` as a parameter to the test function. This is how
  > pytest knows to use it as a fixture.

  ### `capsys`

  In our example, if the request is unsuccessful, we log an error message with
  `print` rather than `logging`. We can test that this message is printed
  correctly using `capsys` to check the stdout:

  ```py
  def test_http_error(capsys):
      with patch("requests.get") as mock_get:
          mock_get.return_value = Mock(ok=False, status_code=404)

          # Raise an HTTP error when raise_for_status is called
          mock_get.return_value.raise_for_status.side_effect = RequestException()

          result = get_articles("some_type")

      captured = capsys.readouterr()
      assert "An error occurred" in captured.out
  ```

  ### `excinfo`

raw_content:
  ---
  tags: [python, testing]
  ---

  # Testing Python code

  ## `pytest`

  Pytest is the most popular testing library for Python. It is not included with
  the Python standard library so it must be installed with
  [pip](Python_package_management.md).
  While it does not include a declaration library, it is robust enough to handle
  most scenarios having a rich and expressive set of constructs and decorators
  that let you declare what your tests should do, under what conditions they
  should run, and how they should interact with the rest of your system.

  ### Using `pytest`

  - Pytest will automatically detect test files so long as they are named
    appropriately. E.g. for a module called `lorem`, it will detzect the unit test
    files `lorem_test.py` and `test_lorem.py`.
  - In order to detect tests it should be run from a directory level above them

  ### Examples

  Here is a basic example of using pytest for a local module callled `palindrome`:

  ```py
  import palindrome

  def test_is_palindrome():
      assert palindrome.is_palindrome('soros')
      assert palindrome.is_palindrome('torot')
      assert not palindrome.is_palindrome('chair')
  ```

  ## Mocking

  `patch()` and `Mock` enable us to mock objects whilst testing (classes,
  functions, methods and properties belonging). They are used in combination.

  The `@patch` decorator temporarily replaces a specified object in your code with
  a mock object and restores the original object after the test is complete

  A Mock object simulates the object it replaces so that the object behaves as
  expected during testing. For example, if your code calls
  `some_function.some_method()`, and `some_method` is mocked, calling
  `some_method` will not execute real logic but will interact with the Mock object
  instead. Mock objects record details about how they have been used, like what
  methods have been called, with what arguments, etc., allowing you to make
  assertions about how they have been used.

  > `@patch` and `Mock` work together because a patch is used to replace an object
  > or attribute with a Mock object. `Mock` handles the simulated functionality,
  > and `@patch` designates the real value we are replacing with the mock.

  ### Example case

  I will use the following example from one my projects:

  ```py
  # get_articles.py
  def get_articles(article_type: str) -> Optional[Dict[str, Any]]:
      """Retrieve articles from Pocket API"""

      if POCKET_LAMBDA_ENDPOINT is None:
          logging.error("Error: POCKET_LAMBDA_ENDPOINT envinronment variable is not set")
          return None
      else:
          # Interpolate the article_type into the Pocket request URL
          endpoint = POCKET_LAMBDA_ENDPOINT.format(article_type=article_type)

      try:
          response = requests.get(endpoint)
          response.raise_for_status()
          return response.json()

      except RequestException as e:
          print(f"An error occurred: {e}")
          return None
  ```

  This function: sources a URL from an environment variable, interpolates a query
  string into the URL (which comes in as a parameter), makes a request to the URL,
  and returns the response as JSON.

  It has some safeguards in place:

  - It checks that the environment variable is set
  - It checks that the request was successful

  In the example we could use a Mock object to simulate the response from the
  Pocket API. This would allow us to test the function without having to make a
  real request to the API:

  ```py
  def test_successful_request():
      # Replace the requests.get function with a Mock object (mock_get)
      with patch("requests.get") as mock_get:
          # Specify the return value of the mock_get object)
          mock_get.return_value = Mock(ok=true)
          mock_get.return_value.json.return_value = {"value": "test"}

          # Call the function under test
          result = get_articles("gaby")

      # Assert expected outcomes
      mock_get.assert_called_once_with(endpoint)
      assert result == mock_json_response
  ```

  The example above follows the **Arrange, Act, Assert** pattern:

  | Stage   | Action                                                                          |
  | ------- | ------------------------------------------------------------------------------- |
  | Arrange | Replace the `requests.get` function with `patch` and set properties with `Mock` |
  | Act     | Call the function under test                                                    |
  | Assert  | Assert that the function under test behaved as expected                         |

  ### Alternative mock syntax

  The `with patch(...) as mock_name` syntax is fine for small-scale mocking but
  can become cumbersome when you are mocking several dependencies.

  There is another syntax (which I actually find clearer). Say we have a function
  with three dependencies: `update_worksheet`, `process_articles`, `get_articles`.
  We could mock like so:

  ```py
  @patch("app.update_worksheet")
  @patch("app.process_articles")
  @patch("app.get_articles")
  def test_success(
      mock_get_articles, mock_process_articles, mock_update_worksheet
  ):
      mock_get_articles.return_value = [1, 2, 3]
  ```

  Here the patching is done by the decorator and the mocks are defined as
  parameters to the test function (always in reverse order)

  ### Mock assertion lexicon

  #### `return_value`

  State what the mock should return

  ```py
  my_mocked_function.return_value = ['one', 'two', 'three']
  ```

  #### `call_count`

  Test how many times a dependent function is called

  ```py
  assert my_mocked_function.call_count = 3
  ```

  #### `assert_any_call()`

  Test that a given mock is called at least once during the execution of the
  function under test

  ```py
  my_mocked_function.assert_any_call(some_mocked_return_value)
  ```

  When the output of one function is used as a parameter to another, and we don't
  particularly care about the details of what is concerned we can just pass the
  executed function, e.g:

  ```py
  my_mocked_function.assert_any_call(preceding_function())
  ```

  #### `call_args_list`

  Get a list of all the arguments that a mock object was called with during the
  test.

  `call_args_list` is useful when you want to check the arguments that a mock
  object was called with during the test, especially if the mock object was called
  multiple times with different arguments. You can use it to inspect the arguments
  of each call and make assertions based on them.

  ```py
  second_my_mocked_function_call = my_mocked_function.call_args_list[1]

  # check the first argument of the second call:

  assert second_my_mocked_function_call[0][0] == "expected arg"
  ```

  #### `side_effect`

  Use to trigger a side effect when returning a value from a mock. Most useful for
  mocking exceptions.

  ```py
  my_mocked_function.side_effect = Exception("Some exception raised")
  ```

  ## Testing exceptions with `raises`

  Testing exceptions is quite straightforward. You can use the `raises` helper
  provided by pytest, and combine this with `excinfo` ("exception info") to
  inspect the exception message.

  ```py
  if POCKET_LAMBDA_ENDPOINT is None:
      raise ValueError(
          "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set"
      )
  ```

  Then to test this, we would use pytest's `excinfo` fixture along with `raises`:

  ```py
   with pytest.raises(ValueError) as excinfo:  # Watch for the ValueError
      get_articles("some_type")

      assert "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set" in str(
          excinfo.value
      )
  ```

  We could actually simplify the above test by using the `match` parameter with
  `raise`. This way we do not need the separate assertion:

  ```py
  with pytest.raises(ValueError, match="Error: POCKET_LAMBDA_ENDPOINT environment variable is not set"):
      get_articles("some_type")
  ```

  Note that `excinfo` is best used for testing the exception text that you the
  developer explicitly `raise`. For exceptions tha may occur naturaly in the code
  you are testing, you should use `caplog` or `capsys` (see below).

  ## Before-each and after-each

  When testing functions, we achieve this in Python using `setup_function` and
  `teardown_function` methods. These methods are called before and after each test
  method respectively.

  To apply a "before each" to _every test_ just put your setup function and/or
  teardown function at the top level of your test module.

  For example, below we set and remove an env var before and after each test:

  ```py
  @pytest.fixture(scope="function") # specify that this fixture should be run before each function test
  def setup_function():
      print("Setting up test environment...")
      os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"


  def teardown_function():
      print("Tearing down test environment...")
      del os.environ["POCKET_LAMBDA_ENDPOINT"]
  ```

  If the setup/teardown should only be applied to a subset of tests, just pass the
  name of the fixture as a parameter to the test function:

  ```py
  def some_function(setup_function):
      # setup_function will be run before this test
  ```

  You don't need to use the names `setup_function` and `teardown_function` so long
  as you are passing the fixture as a parameter.

  You can also use `yield` to combine the setup and teardown into a single
  function:

  ```py
  @pytest.fixture(scope="function")
  def setup_function():
      os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"
      yield
      del os.environ["POCKET_LAMBDA_ENDPOINT"]
  ```

  ### Another example:

  The following test suite uses the same three mocked functions in every test. The
  following set-up assigns the mocks before each test and resets after each
  individual test has run:

  ```py
  @pytest.fixture(scope="function")
  def setup_function():
      with patch("app.get_articles") as mock_get_articles, patch(
          "app.process_articles"
      ) as mock_process_articles, patch("app.update_worksheet") as mock_update_worksheet:
          yield mock_get_articles, mock_process_articles, mock_update_worksheet
  ```

  Then to use:

  ```py
  def individual_test(setup_function):
      mock_get_articles, mock_process_articles, mock_update_worksheet = setup_function
      # Now each mock can be referenced using the vars above

  ```

  ## Parameterized tests

  For a sequence of tests that are repetitive, to avoid repeating the same code
  over and over again, we can use parameterized tests. This is where we pass in a
  list of parameters to the test function and the test function is run once for
  each parameter.

  For example, in the function below I am handling numerous possible Exceptions
  that could be raised by the `requests.get` method:

  ```py
      try:
          response = requests.get(endpoint)
          response.raise_for_status()
          return response.json()

      except HTTPError as http_err:
          logging.error(f"HTTP Error occurred: {http_err}")

      except ConnectionError as conn_err:
          logging.error(f"Connection Error occurred: {conn_err}")

      except Timeout as timeout_err:
          logging.error(f"Timeout Error occurred: {timeout_err}")

      except RequestException as e:
          logging.error(f"Request Exception occurred: {e}")

      return None
  ```

  Instead of writing something like the following for each of the four exceptions:

  ```py

   def test_exception_generic(caplog):
      with patch("requests.get", side_effect=RequestException("Some error")):
          result = get_articles("some_type")

      assert "Request Exception occurred" in caplog.text
      assert result is None
  ```

  I could parameterize like so:

  ```py
  @pytest.mark.parametrize(
      "exception_type, log_message",
      [
          (RequestException, "Request Exception occurred: "),
          (HTTPError, "HTTP Error occurred: "),
          (Timeout, "Timeout Error occurred: "),
          (ConnectionError, "Connection Error occurred: "),
      ],
  )
  def test_exceptions(caplog, exception_type, log_message):
      with patch("requests.get", side_effect=exception_type("Some error")):
          result = get_articles("some_type")

      assert log_message in caplog.text
      assert result is None
  ```

  ## Caplog, syslog, excinfo

  `caplog` and `capsys` are built-in pytest fixtures. `caplog` lets you test log
  messages. `capsys` lets you test stdout and stderr. As such they are very useful
  when testing that error messages are logged correctly.

  ### `caplog`

  In our example, if the endpoing environment is not set, we log an error message.
  We can test that this message is logged correctly using `caplog`:

  ```py
  def test_no_endpoint_env_var(caplog):
      os.environ.pop("POCKET_LAMBDA_ENDPOINT", None)  # Remove env variable if it exists

      with caplog.at_level(logging.ERROR):
          result = get_articles("some_type")

      assert (
          "Error: POCKET_LAMBDA_ENDPOINT environment variable is not set" in caplog.text
      )
      assert result is None
  ```

  > Note tha we pass in `caplog` as a parameter to the test function. This is how
  > pytest knows to use it as a fixture.

  ### `capsys`

  In our example, if the request is unsuccessful, we log an error message with
  `print` rather than `logging`. We can test that this message is printed
  correctly using `capsys` to check the stdout:

  ```py
  def test_http_error(capsys):
      with patch("requests.get") as mock_get:
          mock_get.return_value = Mock(ok=False, status_code=404)

          # Raise an HTTP error when raise_for_status is called
          mock_get.return_value.raise_for_status.side_effect = RequestException()

          result = get_articles("some_type")

      captured = capsys.readouterr()
      assert "An error occurred" in captured.out
  ```

  ### `excinfo`


path: zk/Testing_with_Jest.md
sortable_path: zkTesting_with_Jest.md
title: Testing with Jest
lead: ## Mocking classes/modules
checksum: 073f7ee1dd7b138b9e24d7765cf0ae3b60643eb0ef5c9f391187fd72c1e98968
created: 2024-03-30 09:03:21.426349635+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","testing","jest"]}
body:
  ## 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'
  }
  ```

raw_content:
  ---
  tags: [javascript, testing, jest]
  ---

  # 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'
  }
  ```


