# notes

path: zk/Validating_Mongoose_schemas.md
sortable_path: zkValidating_Mongoose_schemas.md
title: Validating Mongoose schemas
lead: Let's say we have the following schema:
checksum: 847b00e5d4138313509f38e42afa01586c9e0fa1e3cd708baf6a709aafe2702a
created: 2024-03-30 09:03:21.840865001+00:00
modified: 2024-06-16 17:34:43.572142491+00:00
metadata: {"tags":["mongo-db","mongoose","node-js","databases"]}
body:
  Let's say we have the following schema:

  ```js
  const courseSchema = new mongoose.Schema({
    name: { type: String, required: true, minlength: 5, maxlength: 255 },
    author: String,
    tags: [String],
    data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
    isPublished: Boolean,
  });
  ```

  We set our validation criteria as the second property for each schema value. If
  it does not obtain, an exception will be thrown when we attempt to modify the
  database. This will most likely take the form of a Promise rejection.

  Note that this validation only occurs at the level of Mongoose. There is no
  mechanism for running the validation within the database itself. This is one of
  the ways that Mongo differs from an SQL database where you would be able to set
  the property of `required` for a cell in the table. If we didn't set any
  validation via Mongoose, Mongo would accept whatever we sent to it.

  What is the relationship between this Mongoose validation and the
  [Joi](Validation_in_NodeJS.md) validation that we
  use when validating API requests in Node/Express? They complement each other. We
  use Joi to validate the client request to the API. If this is valid, the process
  would then move onto the next stage which would be transforming the data from a
  REST request to a database request implemented through Mongoose, where a second
  layer of validation would appy. We would also have validation on the
  client-side.

  ## Validator functions

  Instead of simply applying a built-in validator like `required`, we can instead
  pass a function that validates agains the validation status of another property
  in the schema. For instance: make the `price` property required only if the
  entry has `true` for `isPublished`:

  ```js
  const courseSchema = new mongoose.Schema({
    ...
    isPublished: Boolean,
    price: {
      type: Number,
      required: function() {return this.isPublished}
    }
  });
  ```

  ## Enum validators

  An enum validator enables us to ensure that whatever value is passed when
  instantiating a document that is of a given schema type, it must be one of a
  finite set of values:

  ```js
  const anotherSchema = new mongoose.Schema({
    sex: {
      type: String,
      enum: ["male", "female"],
    },
  });
  ```

raw_content:
  ---
  tags:
    - mongo-db
    - mongoose
    - node-js
    - databases
  ---

  # Validating Mongoose schemas

  Let's say we have the following schema:

  ```js
  const courseSchema = new mongoose.Schema({
    name: { type: String, required: true, minlength: 5, maxlength: 255 },
    author: String,
    tags: [String],
    data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
    isPublished: Boolean,
  });
  ```

  We set our validation criteria as the second property for each schema value. If
  it does not obtain, an exception will be thrown when we attempt to modify the
  database. This will most likely take the form of a Promise rejection.

  Note that this validation only occurs at the level of Mongoose. There is no
  mechanism for running the validation within the database itself. This is one of
  the ways that Mongo differs from an SQL database where you would be able to set
  the property of `required` for a cell in the table. If we didn't set any
  validation via Mongoose, Mongo would accept whatever we sent to it.

  What is the relationship between this Mongoose validation and the
  [Joi](Validation_in_NodeJS.md) validation that we
  use when validating API requests in Node/Express? They complement each other. We
  use Joi to validate the client request to the API. If this is valid, the process
  would then move onto the next stage which would be transforming the data from a
  REST request to a database request implemented through Mongoose, where a second
  layer of validation would appy. We would also have validation on the
  client-side.

  ## Validator functions

  Instead of simply applying a built-in validator like `required`, we can instead
  pass a function that validates agains the validation status of another property
  in the schema. For instance: make the `price` property required only if the
  entry has `true` for `isPublished`:

  ```js
  const courseSchema = new mongoose.Schema({
    ...
    isPublished: Boolean,
    price: {
      type: Number,
      required: function() {return this.isPublished}
    }
  });
  ```

  ## Enum validators

  An enum validator enables us to ensure that whatever value is passed when
  instantiating a document that is of a given schema type, it must be one of a
  finite set of values:

  ```js
  const anotherSchema = new mongoose.Schema({
    sex: {
      type: String,
      enum: ["male", "female"],
    },
  });
  ```


path: zk/Validity_and_entailment.md
sortable_path: zkValidity_and_entailment.md
title: Validity
lead: ### Informal definition
checksum: 6584299fc0369b2b59b2914c24ce7a50c67c1c51701beacf50c231b8f29309fe
created: 2024-03-30 09:03:21.866073262+00:00
modified: 2024-06-16 16:53:19.349602968+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  ### Informal definition

  In order to say whether an argument is 'good' or 'bad' we must have criteria of
  evaluation. in logic there are different criteria of evaluation:

  - **Deductive validity**

    An **argument is deductively valid if and only if it is not possible for the
    premises to be true and the conclusion false**. Linking to consistency: it is
    not possible to consistently assert all of the premises but deny the
    conclusion.

  - **Inductive strength**

    We do not say that inductive arguments have 'validity' because despite
    inductive premises being true, the conclusion may be falsifiable. Therefore we
    say inductive 'strength' rather than 'validity'. An argument is inductively
    strong if and only if the conclusion is probably true given the premises.

  #### Demonstration

  The Socrates demonstration above is an example of deductive validity.

  The following is an example of an argument that is inductively strong:

  ```
  99% of deaf persons have no musical talent.
  Beethoven was deaf.
  ___________________________________________
  Beethoven had no musical talent.
  ```

  The test for a strong inductive argument is not whether the conclusion is true,
  rather it concerns the evidence the premises provide in support of the
  conclusion.

  > In propositional logic we are concerned solely with deductive validity or
  > invalidity.

  ### Formal definition

  > An argument is truth-functionally valid if and only if there is no
  > truth-assignment on which all the premises are true and the conclusion is
  > false.

  Linking this to derivation, we say:

  > In a system of derivation in propositional logic, an argument is valid if the
  > conclusion of the argument is derivable within the system of derivation from
  > the set consisting of the premises, and invalid otherwise.

  ### Demonstration

  The inference from the set ${P, P \rightarrow Q}$ to $Q$ is valid

  ### Truth-table

  | $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
  | --- | --- | ----------------- | --- | --- | ---------- |
  | T   | T   | T                 | T   | T   | Valid      |
  | T   | F   | F                 | T   | F   |            |
  | F   | T   | T                 | F   | T   |            |

  ## Entailment

  ### Informal definition

  Entailment as a concept is almost identical to validity. We say that a
  proposition is entailed by a set of propositions if it is not possible for every
  member of this set to be true and the proposition to be false.

  The difference with validity resides in the fact that the propositions are
  distinguished in terms of whether they are premises or a conclusion. So,
  technically, validity is a subclass of entailment. A case of entailment where we
  distinguish propositions in terms of whether they are premises or conclusions. A
  proposition may be entailed by a given set without that proposition being the
  _conclusion_ of the set and where the set is a syllogism.

  ### Formal definition

  > A finite set of sentences $\Gamma$ $\vdash$ $P$ if and only if there is no
  > truth-assignment in which every member of $\Gamma$ is true and $P$ is false.

  #### Informal demonstration

  ```
  It is raining.
  If it is raining then the pavement will be wet.
  The pavement is wet.
  ```

  #### Formal demonstration

  $$
    \{ P, P\rightarrow Q   \} \vdash Q
  $$

  #### Truth-table

  | $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
  | --- | --- | ----------------- | --- | --- | ---------- |
  | T   | T   | T                 | T   | T   | Valid      |
  | T   | F   | F                 | T   | F   |            |
  | F   | T   | T                 | F   | T   |            |

raw_content:
  ---
  tags:
    - propositional-logic
    - logic
  ---

  ## Validity

  ### Informal definition

  In order to say whether an argument is 'good' or 'bad' we must have criteria of
  evaluation. in logic there are different criteria of evaluation:

  - **Deductive validity**

    An **argument is deductively valid if and only if it is not possible for the
    premises to be true and the conclusion false**. Linking to consistency: it is
    not possible to consistently assert all of the premises but deny the
    conclusion.

  - **Inductive strength**

    We do not say that inductive arguments have 'validity' because despite
    inductive premises being true, the conclusion may be falsifiable. Therefore we
    say inductive 'strength' rather than 'validity'. An argument is inductively
    strong if and only if the conclusion is probably true given the premises.

  #### Demonstration

  The Socrates demonstration above is an example of deductive validity.

  The following is an example of an argument that is inductively strong:

  ```
  99% of deaf persons have no musical talent.
  Beethoven was deaf.
  ___________________________________________
  Beethoven had no musical talent.
  ```

  The test for a strong inductive argument is not whether the conclusion is true,
  rather it concerns the evidence the premises provide in support of the
  conclusion.

  > In propositional logic we are concerned solely with deductive validity or
  > invalidity.

  ### Formal definition

  > An argument is truth-functionally valid if and only if there is no
  > truth-assignment on which all the premises are true and the conclusion is
  > false.

  Linking this to derivation, we say:

  > In a system of derivation in propositional logic, an argument is valid if the
  > conclusion of the argument is derivable within the system of derivation from
  > the set consisting of the premises, and invalid otherwise.

  ### Demonstration

  The inference from the set ${P, P \rightarrow Q}$ to $Q$ is valid

  ### Truth-table

  | $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
  | --- | --- | ----------------- | --- | --- | ---------- |
  | T   | T   | T                 | T   | T   | Valid      |
  | T   | F   | F                 | T   | F   |            |
  | F   | T   | T                 | F   | T   |            |

  ## Entailment

  ### Informal definition

  Entailment as a concept is almost identical to validity. We say that a
  proposition is entailed by a set of propositions if it is not possible for every
  member of this set to be true and the proposition to be false.

  The difference with validity resides in the fact that the propositions are
  distinguished in terms of whether they are premises or a conclusion. So,
  technically, validity is a subclass of entailment. A case of entailment where we
  distinguish propositions in terms of whether they are premises or conclusions. A
  proposition may be entailed by a given set without that proposition being the
  _conclusion_ of the set and where the set is a syllogism.

  ### Formal definition

  > A finite set of sentences $\Gamma$ $\vdash$ $P$ if and only if there is no
  > truth-assignment in which every member of $\Gamma$ is true and $P$ is false.

  #### Informal demonstration

  ```
  It is raining.
  If it is raining then the pavement will be wet.
  The pavement is wet.
  ```

  #### Formal demonstration

  $$
    \{ P, P\rightarrow Q   \} \vdash Q
  $$

  #### Truth-table

  | $P$ | $Q$ | $P \rightarrow Q$ | $P$ | $Q$ | Assessment |
  | --- | --- | ----------------- | --- | --- | ---------- |
  | T   | T   | T                 | T   | T   | Valid      |
  | T   | F   | F                 | T   | F   |            |
  | F   | T   | T                 | F   | T   |            |


path: zk/Viewing_remote_changes_without_merging.md
sortable_path: zkViewing_remote_changes_without_merging.md
title: Viewing remote changes without merging
lead:
  ```
  git fetch origin/master
  git log origin/main
  git show origin/master
  ```

body:
  ```
  git fetch origin/master
  git log origin/main
  git show origin/master
  ```

checksum: 1a5f587f96e84a733ebdf522999e5efdca8e55052d1f846baa71e7e768081e7c
created: 2024-03-30 09:03:21.882007116+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
raw_content:
  ---
  tags: [git]
  ---

  # Viewing remote changes without merging

  ```
  git fetch origin/master
  git log origin/main
  git show origin/master
  ```


path: zk/Views_in_relational_databases.md
sortable_path: zkViews_in_relational_databases.md
title: Views in relational databases
checksum: f48de8e2b132aa72d28eefba0fb3508f1baac92593009b7f0bd7be27e3a539ed
created: 2024-03-30 09:03:21.885545399+00:00
modified: 2024-06-16 17:35:09.666489341+00:00
metadata: {"tags":["databases"]}
lead:
  A view is a virtual table that is based on the result-set of a query. Although
  it doesn't actually exist in the same manner as an actual table it has exactly
  the same properties and functionality. Rather than adding the raw data manually,
  you derive it from logic applied to existing actual tables.

body:
  A view is a virtual table that is based on the result-set of a query. Although
  it doesn't actually exist in the same manner as an actual table it has exactly
  the same properties and functionality. Rather than adding the raw data manually,
  you derive it from logic applied to existing actual tables.

  This is a good way of dynamically generating data and is often employed as a way
  of creating mutations without changing the underlying data structure. In SQL,
  views can be created by combining `PRIMARY` and `FOREIGN` keys.

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

  # Views in relational databases

  A view is a virtual table that is based on the result-set of a query. Although
  it doesn't actually exist in the same manner as an actual table it has exactly
  the same properties and functionality. Rather than adding the raw data manually,
  you derive it from logic applied to existing actual tables.

  This is a good way of dynamically generating data and is often employed as a way
  of creating mutations without changing the underlying data structure. In SQL,
  views can be created by combining `PRIMARY` and `FOREIGN` keys.


path: zk/Voltage.md
sortable_path: zkVoltage.md
title: Voltage
lead: ## Difference of potential and the transfer of energy
checksum: aad60b4e37e2791658c5676cb4e0c66e309094763d8e8260822ed70057858666
created: 2024-03-30 09:03:21.904807011+00:00
modified: 2024-05-12 10:51:33.662225809+00:00
metadata: {"tags":["physics","electricity"]}
body:
  ## Difference of potential and the transfer of energy

  We noted in the discussion of [current](Current.md) that current flows when
  there is a difference of potential between two points with negatively charged
  atoms at one point and positively charged atoms at the other.

  _Difference of potential_ is the same thing as voltage. Voltage is essential to
  current because it is the force that enables the current to flow.

  Without voltage there can be no current because in their natural state, the
  electrons in an atom are **in random motion with no direction. To produce a
  current, energy must be imparted to the electrons so that they all flow in the
  same direction.**

  Voltage is the application of this energy. Any
  [form of energy](Voltage_sources.md) that dislodges electrons from atoms can be
  used to produce current. Thus:

  > Voltage is the work required per coulomb to move a charge from one point to
  > another.

  ### Voltage exists even without current

  Given that voltage is the force that generates current, it would be natural to
  think that voltage only exists when a voltage source (such as a
  [battery](Cells_and_batteries.md)) is connected to a circuit. This however is
  not the case. Even if a 9V battery isn't connected to anything it still has a
  difference of potential of 9-volts accross its terminals. Remember voltage is
  _potential energy_ not just the actualisation of that energy.

  ## Voltage rise and voltage drops

  In circuits there are actually two types of voltage:

  1. Voltage rise
  2. Voltage drop

  ### Voltage rise

  When we introduce potential energy into a ciruit in the form of voltage, this is
  a voltage rise. The current flows from the negative terminal of the voltage
  source and returns to the positive terminal of the voltage source.

  A 12V battery connected to a circuit gives it a voltage rise of 12 volts.

  ### Voltage drop

  Voltage drop is the corrolary to voltage rise. It is the loss of energy that the
  electrons of the circuit current experience as a result of encountering
  resistance.

  As they move through the circuit the electrons encounter a **load** which is
  what we call resistance to the flow of current. As they run into this, they give
  up their energy. The relinquishing of energy happens in the form of a conversion
  of electrical energy to heat (hence why computers heat up). The amount lost is
  equal to the amount of energy imparted by the voltage rise.

  > The voltage drop in a circuit equals the the voltage rise of the circuit
  > because energy cannot be created or destroyed, only changed to another form.
  > When a voltage rise is converted to a voltage drop we say that **the energy
  > has been _consumed_ by the circuit**.

  #### Examples

  - If a 12V source is connected to a 12V lamp, the source supplies a 12V voltage
    rise and the lamp produces a 12V voltage drop.
  - If two identical 6V lamps are connected in series to the same 12V source, each
    lamp produces a 6V drop for a total of 12 volts
  - If two different lamps are connected in series to to a 12V source: a 3V and a
    9V lamp, the 9V lamp produces a drop of 9V and the 3V lamp produces a drop of
    3V. The sum of the voltage drops equals the voltage rise of 12 volts.

  These examples demonstrate that the voltage rise: voltage drop ratio always
  evens out.

  ### Kirchoff's Voltage Law

  The relationship between voltage rise and voltage drop is expressed in
  Kirchoff's Voltage Law:

  > The sum of the voltages around any closed loop in a circuit must be zero.

  The application of the Law is illustrated in the following diagram:

  ![](/img/voltage-drop.png)

  The explanation for the voltage drop at the positions $V^{A}$ and $V^{D}$ are
  obvious enough: they are at the beginning and end of the loop so are equal to
  the maximal voltage rise and minimal voltage drop, respectively.

  We can work out the voltage of the remaining voltage points by inverting
  [Ohm's Law](Ohms_Law.md): $V = I \times R$:

  For the voltage at $V^{B}$:

  $$
    0.5\textsf{mA} \times \textsf{4}k\Omega = 2 \textsf{V}
  $$

  For the voltage at $V^{C}$:

  $$
    0.5\textsf{mA} \times \textsf{6}k\Omega = 3 \textsf{V}
  $$

  The total drops (2V, 3V, 5V) are equal to the initial volatage rise (10V)

  ## Distinguishing _voltage_ from _electric field_

  It can be confusing that two different symbols often seemed to be used
  interchangeably when talking about voltage: $V$ and $E$. However, while they
  broadly point to the same phenomenon there is a difference in emphasis.

  - $V$ stands for volts or voltage conceived purely in terms of the difference in
    potential between two points: the positive and negative terminals
  - $E$ stands for electric field. This is the field that surround each electric
    charge and exerts force on all other charges in the field, attracting or
    repelling them. So it is more the physical process that the volatage
    represents rather than the numerical representation of the potential between
    the terminals.

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

  # Voltage

  ## Difference of potential and the transfer of energy

  We noted in the discussion of [current](Current.md) that current flows when
  there is a difference of potential between two points with negatively charged
  atoms at one point and positively charged atoms at the other.

  _Difference of potential_ is the same thing as voltage. Voltage is essential to
  current because it is the force that enables the current to flow.

  Without voltage there can be no current because in their natural state, the
  electrons in an atom are **in random motion with no direction. To produce a
  current, energy must be imparted to the electrons so that they all flow in the
  same direction.**

  Voltage is the application of this energy. Any
  [form of energy](Voltage_sources.md) that dislodges electrons from atoms can be
  used to produce current. Thus:

  > Voltage is the work required per coulomb to move a charge from one point to
  > another.

  ### Voltage exists even without current

  Given that voltage is the force that generates current, it would be natural to
  think that voltage only exists when a voltage source (such as a
  [battery](Cells_and_batteries.md)) is connected to a circuit. This however is
  not the case. Even if a 9V battery isn't connected to anything it still has a
  difference of potential of 9-volts accross its terminals. Remember voltage is
  _potential energy_ not just the actualisation of that energy.

  ## Voltage rise and voltage drops

  In circuits there are actually two types of voltage:

  1. Voltage rise
  2. Voltage drop

  ### Voltage rise

  When we introduce potential energy into a ciruit in the form of voltage, this is
  a voltage rise. The current flows from the negative terminal of the voltage
  source and returns to the positive terminal of the voltage source.

  A 12V battery connected to a circuit gives it a voltage rise of 12 volts.

  ### Voltage drop

  Voltage drop is the corrolary to voltage rise. It is the loss of energy that the
  electrons of the circuit current experience as a result of encountering
  resistance.

  As they move through the circuit the electrons encounter a **load** which is
  what we call resistance to the flow of current. As they run into this, they give
  up their energy. The relinquishing of energy happens in the form of a conversion
  of electrical energy to heat (hence why computers heat up). The amount lost is
  equal to the amount of energy imparted by the voltage rise.

  > The voltage drop in a circuit equals the the voltage rise of the circuit
  > because energy cannot be created or destroyed, only changed to another form.
  > When a voltage rise is converted to a voltage drop we say that **the energy
  > has been _consumed_ by the circuit**.

  #### Examples

  - If a 12V source is connected to a 12V lamp, the source supplies a 12V voltage
    rise and the lamp produces a 12V voltage drop.
  - If two identical 6V lamps are connected in series to the same 12V source, each
    lamp produces a 6V drop for a total of 12 volts
  - If two different lamps are connected in series to to a 12V source: a 3V and a
    9V lamp, the 9V lamp produces a drop of 9V and the 3V lamp produces a drop of
    3V. The sum of the voltage drops equals the voltage rise of 12 volts.

  These examples demonstrate that the voltage rise: voltage drop ratio always
  evens out.

  ### Kirchoff's Voltage Law

  The relationship between voltage rise and voltage drop is expressed in
  Kirchoff's Voltage Law:

  > The sum of the voltages around any closed loop in a circuit must be zero.

  The application of the Law is illustrated in the following diagram:

  ![](/img/voltage-drop.png)

  The explanation for the voltage drop at the positions $V^{A}$ and $V^{D}$ are
  obvious enough: they are at the beginning and end of the loop so are equal to
  the maximal voltage rise and minimal voltage drop, respectively.

  We can work out the voltage of the remaining voltage points by inverting
  [Ohm's Law](Ohms_Law.md): $V = I \times R$:

  For the voltage at $V^{B}$:

  $$
    0.5\textsf{mA} \times \textsf{4}k\Omega = 2 \textsf{V}
  $$

  For the voltage at $V^{C}$:

  $$
    0.5\textsf{mA} \times \textsf{6}k\Omega = 3 \textsf{V}
  $$

  The total drops (2V, 3V, 5V) are equal to the initial volatage rise (10V)

  ## Distinguishing _voltage_ from _electric field_

  It can be confusing that two different symbols often seemed to be used
  interchangeably when talking about voltage: $V$ and $E$. However, while they
  broadly point to the same phenomenon there is a difference in emphasis.

  - $V$ stands for volts or voltage conceived purely in terms of the difference in
    potential between two points: the positive and negative terminals
  - $E$ stands for electric field. This is the field that surround each electric
    charge and exerts force on all other charges in the field, attracting or
    repelling them. So it is more the physical process that the volatage
    represents rather than the numerical representation of the potential between
    the terminals.


path: zk/Voltage_sources.md
sortable_path: zkVoltage_sources.md
title: Voltage sources
lead: The following phenomena are the main sources that we use to generate voltage:
checksum: 88d7509073e3453a58af7a34f89f36e3de1f0212048f3255ad57489a3e2bf0a2
created: 2024-03-30 09:03:21.931596527+00:00
modified: 2024-05-16 06:09:38.490863436+00:00
metadata: {"tags":["physics","electricity"]}
body:
  The following phenomena are the main sources that we use to generate voltage:

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

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

  ### Magentism (electrical generators)

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

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

  #### AC/DC

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

  - **Directed current**

    - The electrons flow in only one direction

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

  ### Chemicals (cells and batteries)

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

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

  ### Light (photovoltaic cells)

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

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

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

  # Voltage sources

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

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

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

  ### Magentism (electrical generators)

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

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

  #### AC/DC

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

  - **Directed current**

    - The electrons flow in only one direction

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

  ### Chemicals (cells and batteries)

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

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

  ### Light (photovoltaic cells)

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

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


path: zk/What_are_disks.md
sortable_path: zkWhat_are_disks.md
title: What are disks?
lead:
  A disk is a mass storage [block_device](Devices.md) which we
  can write to and read from.

checksum: e2afba648e34963a7b5c9f4a8b9bb857ce1540de0997c2f7291479de9d905c5b
created: 2024-03-30 09:03:21.942804056+00:00
modified: 2024-06-16 17:35:41.921079185+00:00
metadata: {"tags":["disks","computer-architecture"]}
body:
  A disk is a mass storage [block_device](Devices.md) which we
  can write to and read from.

  ## SCSI

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

  ## Disk schematic

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

  ![](/img/harddisk.png)

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

raw_content:
  ---
  tags:
    - disks
    - computer-architecture
  ---

  # What are disks?

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

  ## SCSI

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

  ## Disk schematic

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

  ![](/img/harddisk.png)

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


path: zk/Whole_numbers.md
sortable_path: zkWhole_numbers.md
title: The set of whole numbers
lead: We recall the set of whole numbers:
checksum: 55a213e7c8d3fd57417fb5291e2452abb12fdc19266c9a6c00130544e5b85789
created: 2024-03-30 09:03:21.964186692+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra"]}
body:
  We recall the set of whole numbers:

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

  # The properties of $\mathbb{W}$

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

  ## The commutative property

  ### Addition

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

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

  $$ a + b = b + a $$

  ### Multiplication

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

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

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

  ### Subtraction

  **Subtraction** is not commutative, viz:

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

  ### Division

  Division is not commutative, viz:

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

  ## The associative property

  ### Addition

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

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

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

  ### Multiplication

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

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

  ### Subtraction

  Subtraction is not associative, viz:

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

  ### Division

  Division is not associative

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

  ## The property of additive identity

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

  $$ a + 0 = a $$

  We therefore call zero the additive identity: whenever we add zero to a whole
  number, the sum is equal to the whole number itself.

  ## The property of multiplicative identity

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

  $$ (a \cdot 1 = a) = (1 \cdot a = a) $$

  ## Multiplication by zero

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

  $$ (a \cdot 0 = 0) = (0 \cdot a = 0) $$

  ## Division by zero

  Division by zero is **undefined** but zero divided is zero.

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

  # The set of whole numbers

  We recall the set of whole numbers:

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

  # The properties of $\mathbb{W}$

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

  ## The commutative property

  ### Addition

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

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

  $$ a + b = b + a $$

  ### Multiplication

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

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

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

  ### Subtraction

  **Subtraction** is not commutative, viz:

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

  ### Division

  Division is not commutative, viz:

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

  ## The associative property

  ### Addition

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

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

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

  ### Multiplication

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

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

  ### Subtraction

  Subtraction is not associative, viz:

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

  ### Division

  Division is not associative

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

  ## The property of additive identity

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

  $$ a + 0 = a $$

  We therefore call zero the additive identity: whenever we add zero to a whole
  number, the sum is equal to the whole number itself.

  ## The property of multiplicative identity

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

  $$ (a \cdot 1 = a) = (1 \cdot a = a) $$

  ## Multiplication by zero

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

  $$ (a \cdot 0 = 0) = (0 \cdot a = 0) $$

  ## Division by zero

  Division by zero is **undefined** but zero divided is zero.


path: zk/Why_computers_use_binary.md
sortable_path: zkWhy_computers_use_binary.md
title: Why computers use binary
lead: ## Now we know how binary works, how does it relate to computing?
checksum: f1e48d431648ff5f081d982bd3cde7673eb114fa43c6c62f39f4d8e9f23817f3
created: 2024-03-30 09:03:22.004239333+00:00
modified: 2024-06-16 17:35:49.054690949+00:00
metadata: {"tags":["binary","computer-architecture"]}
body:
  ## Now we know how binary works, how does it relate to computing?

  The reason is straight forward: it is the simplest way on the level of pure
  engineering of representing numerical and logical values; both of which are the
  basic foundations of programming. An electronic circuit or transistor only needs
  to represent two states: on (1) and off (0) which corresponds to the switch on
  an electrical circuit. A single circuit representing the binary values of 1 and
  0:

  ![multi_on_off 1.gif](multi_on_off.gif)

  It would be much more complicated to have to represent ten different states
  under the decimal number system, although denary computers do exist.

  If we want more digits, we just need to add in more circuits, and we can
  represent as large a binary number as we need. We just need one switch for every
  digit we want to represent. The switches used in modern computers are so cheap
  and so small that billions can be fitted on a single circuit board.

  ![multiple_circuits.gif](multiple_circuits.gif)

  When we use the term 'switch' we actually mean the transistor components of a
  circuit. We don't need to know the physical details at this level but we can say
  that a transistor turns a current on and off. They can also be used to amplify
  the current.

  On the level of electrical engineering and in the subsequent examples using a
  light bulb and a simple circuit, the switch being OFF corresponds to the light
  being ON, this is because the switch breaks the current. So when it is unbroken,
  the current passes to the bulb. This also means that 1 corresponds to the switch
  being OFF and 0 corresponds to the switch being ON which can be confusing at
  first.

  ## From circuits to programs

  The following breaks down how we get from the binary number system to electrical
  circuits to computer programs:

  1. ”Data”= a piece or pieces of **information**

  1. In computing all data is represented in **binary form:**

     2.1. ”Binary” means that the value of a piece of data is exclusively one
     thing or another

     2.2. The values in binary code are exclusively 1 and 0 (either a piece of
     data is a 1 or it is a 0, it can never be both). Binary can also be expressed
     in logical terms where 1 is equal to `true` and 0 is equal to `false`

  1. The smallest piece of data is a **bit**

  1. We apply the binary number system to bits

  1. Thus by 1-4, **a bit is either 1 or 0**

  1. Binary form bears an isomorphic relation to switches on electrical circuits
     (the hardware of computers). Thus binary code can be _mapped onto circuits_.

     - Circuits are controlled by switches
     - A switch is a binary function: it is either on or off ”On/off”
       corresponding to 1/0.
     - In this way, switches control the flow of electric current

  1. Thus by the above, hardware (which is a physical structure made up of
     electric circuits) is **readily programmable in binary terms**

  1. Restatement of 6: in order for hardware to be programmed the program must
     provide the hardware with something that it can actually perform. The program
     must be formulated in binary code.

raw_content:
  ---
  tags:
    - binary
    - computer-architecture
  ---

  # Why computers use binary

  ## Now we know how binary works, how does it relate to computing?

  The reason is straight forward: it is the simplest way on the level of pure
  engineering of representing numerical and logical values; both of which are the
  basic foundations of programming. An electronic circuit or transistor only needs
  to represent two states: on (1) and off (0) which corresponds to the switch on
  an electrical circuit. A single circuit representing the binary values of 1 and
  0:

  ![multi_on_off 1.gif](multi_on_off.gif)

  It would be much more complicated to have to represent ten different states
  under the decimal number system, although denary computers do exist.

  If we want more digits, we just need to add in more circuits, and we can
  represent as large a binary number as we need. We just need one switch for every
  digit we want to represent. The switches used in modern computers are so cheap
  and so small that billions can be fitted on a single circuit board.

  ![multiple_circuits.gif](multiple_circuits.gif)

  When we use the term 'switch' we actually mean the transistor components of a
  circuit. We don't need to know the physical details at this level but we can say
  that a transistor turns a current on and off. They can also be used to amplify
  the current.

  On the level of electrical engineering and in the subsequent examples using a
  light bulb and a simple circuit, the switch being OFF corresponds to the light
  being ON, this is because the switch breaks the current. So when it is unbroken,
  the current passes to the bulb. This also means that 1 corresponds to the switch
  being OFF and 0 corresponds to the switch being ON which can be confusing at
  first.

  ## From circuits to programs

  The following breaks down how we get from the binary number system to electrical
  circuits to computer programs:

  1. ”Data”= a piece or pieces of **information**

  1. In computing all data is represented in **binary form:**

     2.1. ”Binary” means that the value of a piece of data is exclusively one
     thing or another

     2.2. The values in binary code are exclusively 1 and 0 (either a piece of
     data is a 1 or it is a 0, it can never be both). Binary can also be expressed
     in logical terms where 1 is equal to `true` and 0 is equal to `false`

  1. The smallest piece of data is a **bit**

  1. We apply the binary number system to bits

  1. Thus by 1-4, **a bit is either 1 or 0**

  1. Binary form bears an isomorphic relation to switches on electrical circuits
     (the hardware of computers). Thus binary code can be _mapped onto circuits_.

     - Circuits are controlled by switches
     - A switch is a binary function: it is either on or off ”On/off”
       corresponding to 1/0.
     - In this way, switches control the flow of electric current

  1. Thus by the above, hardware (which is a physical structure made up of
     electric circuits) is **readily programmable in binary terms**

  1. Restatement of 6: in order for hardware to be programmed the program must
     provide the hardware with something that it can actually perform. The program
     must be formulated in binary code.


path: zk/Wildcards_in_SQL.md
sortable_path: zkWildcards_in_SQL.md
title: Wildcards in SQL
lead:
  SQL does not use Regex. Instead it has a simpler glob-like syntax for carrying
  out string matching.

checksum: b761196c7c6f74fc89c73b5473e5d14148d6db91415904bc5456d190063aa12f
created: 2024-03-30 09:03:22.009604092+00:00
modified: 2024-06-15 09:48:37.544444617+00:00
metadata: {"tags":["SQL","databases"]}
body:
  SQL does not use Regex. Instead it has a simpler glob-like syntax for carrying
  out string matching.

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

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

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

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

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

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

  # Wildcards in SQL

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

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

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

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

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

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


path: zk/Working_with_numbers_in_Bash.md
sortable_path: zkWorking_with_numbers_in_Bash.md
title: Working with numbers in Bash
lead: We distinguish:
checksum: d793b757573d5c77ece45d9b81efbc9a285dfe699f8221faf4f0ab9f095c96c5
created: 2024-03-30 09:03:22.015441917+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  We distinguish:

  - **arithmetic expansion** `$(( ))`
    - returns the result of literal numbers that can then be stored in a variable
  - **artihmetic evaluation** `(( ))`
    - perform calculations on _existing_ variables

  An example of expansion:

  ```bash
  a=3
  ((a += 3))
  echo $a
  # 6
  ((a++))
  # 7
  ```

  > Note: we do not use a dollar-sign when referring to variables within
  > arithmetic evaluation, there is no need. If we do, we get an error. This is
  > because we are using an
  > [expansion](Expansions_and_substitutions.md),
  > therefore the variables are already being interpreted as variables.

  ## Declaring variables as integers

  It is good practice to safeguard against Bash treating numbers as strings to
  declare them as integers in addition to using arithmetic evaluation, e.g:

  ```bash
  declare -i b=3
  ```

  Whilst this isn't a strict type, it means we can do this:

  ```bash
  b=$b+4
  echo b
  # 7
  ```

  Without getting `3+4` in return

  ## No decimals in bash

  Bash does not support decimal calculations natively. This is what you'd get for
  example:

  ```bash
  echo $(( 1/3 ))
  # 0 (not 0.33)
  ```

  So work with decimals you should use `awk` or `bc` ("basic calculations").

  Example of using `bc`:

  ```bash
  declare -i c=1
  declare -i d=3
  e=$(echo "scale=3; $c/$d" | bc)
  # 0.333
  ```

  ## Random numbers

  Generate a pseudo-random number between 1 and 20:

  ```bash
  echo $(( 1 + RANDOM % 10))
  # 18
  ```

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

  # Working with numbers in Bash

  We distinguish:

  - **arithmetic expansion** `$(( ))`
    - returns the result of literal numbers that can then be stored in a variable
  - **artihmetic evaluation** `(( ))`
    - perform calculations on _existing_ variables

  An example of expansion:

  ```bash
  a=3
  ((a += 3))
  echo $a
  # 6
  ((a++))
  # 7
  ```

  > Note: we do not use a dollar-sign when referring to variables within
  > arithmetic evaluation, there is no need. If we do, we get an error. This is
  > because we are using an
  > [expansion](Expansions_and_substitutions.md),
  > therefore the variables are already being interpreted as variables.

  ## Declaring variables as integers

  It is good practice to safeguard against Bash treating numbers as strings to
  declare them as integers in addition to using arithmetic evaluation, e.g:

  ```bash
  declare -i b=3
  ```

  Whilst this isn't a strict type, it means we can do this:

  ```bash
  b=$b+4
  echo b
  # 7
  ```

  Without getting `3+4` in return

  ## No decimals in bash

  Bash does not support decimal calculations natively. This is what you'd get for
  example:

  ```bash
  echo $(( 1/3 ))
  # 0 (not 0.33)
  ```

  So work with decimals you should use `awk` or `bc` ("basic calculations").

  Example of using `bc`:

  ```bash
  declare -i c=1
  declare -i d=3
  e=$(echo "scale=3; $c/$d" | bc)
  # 0.333
  ```

  ## Random numbers

  Generate a pseudo-random number between 1 and 20:

  ```bash
  echo $(( 1 + RANDOM % 10))
  # 18
  ```


path: zk/Zero_property_of_multiplication.md
sortable_path: zkZero_property_of_multiplication.md
lead:
  ---
  tags:
  - prealgebra
  - theorems
  ---

checksum: ab65cf0fbf5ec242a321c119815347b74bba3c9a520fa4fb59b5be4e147f563c
created: 2024-03-30 09:03:22.025204158+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","theorems"]}
body:
  ---
  tags:
    - prealgebra
    - theorems
  ---

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

  $$ a \cdot 0 = 0 $$

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

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

  $$ a \cdot 0 = 0 $$


path: zk/Zip_function_in_Python.md
sortable_path: zkZip_function_in_Python.md
title: zip
checksum: 0e7191e6c8fbb369de0479b6d8f0ebcd60161e6cf2f4f978eb878aa8436e54a1
created: 2024-03-30 09:03:22.028631364+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-structures"]}
lead:
  The `zip` function returns a zip object when you pass in two iterator data types
  (typically two lists). This is an iterator of tuples where the first item in
  each passed iterator is paired together, and then the second item in each passed
  iterator are paired together, and so on.

body:
  The `zip` function returns a zip object when you pass in two iterator data types
  (typically two lists). This is an iterator of tuples where the first item in
  each passed iterator is paired together, and then the second item in each passed
  iterator are paired together, and so on.

  ## Example

  ```py
  a = ("John", "Charles", "Mike")
  b = ("Jenny", "Christy", "Monica", "Vicky")

  x = zip(a,b)

  print(x)
  # <zip object at 0x1514af34c340>

  # To display the resulting tuple in a readable format:

  print(tuple(x))

  (('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
  ```

  As indicated above, if the input iterators are of equal lengths, Python will
  ignore the value in iterator B that doesn't have an equivalent index in iterator
  A.

  ## Real-life example

  ```py
  prompts = [
      "Enter title",
      "Enter author",
      "Enter publication date",
      "Enter year you read the book"
  ]

  keys = ["Title", "Author", "Publication_date", "Date_read"]

  book = {}

  for key, prompt in zip(keys,prompts):
      book[key] = input(prompt + ": ")

  ```

  Here I take the `prompts` and `keys` lists, collate them via `zip` and then loop
  through them to populate the `book` dictionary, which contains properties
  sourced from the `keys` list and values from the user's answers to the
  `prompts`.

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

  # `zip`

  The `zip` function returns a zip object when you pass in two iterator data types
  (typically two lists). This is an iterator of tuples where the first item in
  each passed iterator is paired together, and then the second item in each passed
  iterator are paired together, and so on.

  ## Example

  ```py
  a = ("John", "Charles", "Mike")
  b = ("Jenny", "Christy", "Monica", "Vicky")

  x = zip(a,b)

  print(x)
  # <zip object at 0x1514af34c340>

  # To display the resulting tuple in a readable format:

  print(tuple(x))

  (('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
  ```

  As indicated above, if the input iterators are of equal lengths, Python will
  ignore the value in iterator B that doesn't have an equivalent index in iterator
  A.

  ## Real-life example

  ```py
  prompts = [
      "Enter title",
      "Enter author",
      "Enter publication date",
      "Enter year you read the book"
  ]

  keys = ["Title", "Author", "Publication_date", "Date_read"]

  book = {}

  for key, prompt in zip(keys,prompts):
      book[key] = input(prompt + ": ")

  ```

  Here I take the `prompts` and `keys` lists, collate them via `zip` and then loop
  through them to populate the `book` dictionary, which contains properties
  sourced from the `keys` list and values from the user's answers to the
  `prompts`.


path: zk/fs.md
sortable_path: zkfs.md
title: fs module
checksum: acd2f1a9993165caa5ecf4a56b9e9dee29e00696a1f03582e784d576712099d4
created: 2024-03-30 09:03:22.049680323+00:00
modified: 2024-06-16 17:24:29.452883683+00:00
metadata: {"tags":["node-js"]}
lead:
  File System is an essential built-in module of Node that contains utility
  methods for working with files and directories.

body:
  File System is an essential built-in module of Node that contains utility
  methods for working with files and directories.

  Every method associated with `fs` has a _blocking_ and _asynchronous_
  implementation. The former obviously blocks the
  [event queue](Event_loop.md), the
  latter does not.

  The synchronous methods are useful to have in some contexts but in general and
  with real-world applications, you should be using the async implementation so as
  to accord with the single-threaded event-driven architecture of Node.

  ## Common I/0 methods

  ### Read directory

  Return a string array of all files in the current directory.

  ```js
  fs.readdir("./", function (err, files) {
    if (err) {
      console.error(err);
    } else {
      console.log(files);
    }
  });
  ```

  ### Read from file

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

  ### Write to file

  ```js
  let md = `A new file`;

  fs.writeFile("testFile.md", md.trim(), function () {
    console.log("File was created");
  });
  ```

  ### Appending to file

  ```js
  fs.appendFile("testFile.md", "new content");
  ```

  ### Create directory

  ```js
  if (!fs.existsSync("directory_name")) {
    fs.mkdir("directory_name", function (err) {
      if (err) {
        console.err(err);
      }
    });
  } else {
    console.warn("Directory already exists");
  }
  ```

  ### Rename and remove files

  ```js
  fs.rename("./filename.js", "./newname.js", function () {
    console.log("file renamed");
  });
  ```

  ```js
  // Remove file
  fs.unlink("./file-to-delete", function (err) {
    if (err) {
      console.error(err);
    }
  });
  ```

  ### Rename and remove directories

  ```js
  // Best to use synchronous method here
  fs.rmSync("/dir", { recursive: true, force: true });
  ```

  ## Streams

  See [Handling streams with fs](Streams_in_NodeJS.md)

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

  # fs module

  File System is an essential built-in module of Node that contains utility
  methods for working with files and directories.

  Every method associated with `fs` has a _blocking_ and _asynchronous_
  implementation. The former obviously blocks the
  [event queue](Event_loop.md), the
  latter does not.

  The synchronous methods are useful to have in some contexts but in general and
  with real-world applications, you should be using the async implementation so as
  to accord with the single-threaded event-driven architecture of Node.

  ## Common I/0 methods

  ### Read directory

  Return a string array of all files in the current directory.

  ```js
  fs.readdir("./", function (err, files) {
    if (err) {
      console.error(err);
    } else {
      console.log(files);
    }
  });
  ```

  ### Read from file

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

  ### Write to file

  ```js
  let md = `A new file`;

  fs.writeFile("testFile.md", md.trim(), function () {
    console.log("File was created");
  });
  ```

  ### Appending to file

  ```js
  fs.appendFile("testFile.md", "new content");
  ```

  ### Create directory

  ```js
  if (!fs.existsSync("directory_name")) {
    fs.mkdir("directory_name", function (err) {
      if (err) {
        console.err(err);
      }
    });
  } else {
    console.warn("Directory already exists");
  }
  ```

  ### Rename and remove files

  ```js
  fs.rename("./filename.js", "./newname.js", function () {
    console.log("file renamed");
  });
  ```

  ```js
  // Remove file
  fs.unlink("./file-to-delete", function (err) {
    if (err) {
      console.error(err);
    }
  });
  ```

  ### Rename and remove directories

  ```js
  // Best to use synchronous method here
  fs.rmSync("/dir", { recursive: true, force: true });
  ```

  ## Streams

  See [Handling streams with fs](Streams_in_NodeJS.md)


path: zk/journald.md
sortable_path: zkjournald.md
title: journald
checksum: 44545669b98d5fb966e0e5acedac5d552eeae71380c97350c99984f74f7fcb04
created: 2024-03-30 09:03:22.082651017+00:00
modified: 2024-06-16 17:26:03.916136562+00:00
metadata: {"tags":["systems-programming","Linux","procedural"]}
lead:
  `journald` is a program that comes as default with [systemd](systemd.md). It is
  a service for collecting and storing system-level log data. I keeps a track of
  all [kernel](The_kernel.md) processes. It is invaluable when tracing the source
  of problems and errors that may arise on the system level. It keeps a track of
  all kernal processes.

body:
  `journald` is a program that comes as default with [systemd](systemd.md). It is
  a service for collecting and storing system-level log data. I keeps a track of
  all [kernel](The_kernel.md) processes. It is invaluable when tracing the source
  of problems and errors that may arise on the system level. It keeps a track of
  all kernal processes.

  ![](/img/journald.png)

  ## `journalctl`

  We use `journalctl` to access the logs. The command by itself outputs the entire
  log which will be huge and hard to scroll through. We can refine the results
  with modifiers.

  ### View logs for a specific process with pid

  ```bash
  journalctl _PID=1234
  ```

  ### View logs for a specific time period

  This can be really helpful since you can bracket the most recent events which
  will be more memorable.

  ```bash
  journalctl -S -1h
  ```

  ### View logs for a specfic systemd unit

  ```bash
  journalctl -u [unit_name] -e
  ```

  ### View boot logs

  ```bash
  journalctl -b
  ```

  #### Identify specific boot

  ```bash
  journalctl --list-boots

  ```

  ### List only kernel entries to the journal

  ```bash
  journalctl -k

  ```

raw_content:
  ---
  tags:
    - systems-programming
    - Linux
    - procedural
  ---

  # `journald`

  `journald` is a program that comes as default with [systemd](systemd.md). It is
  a service for collecting and storing system-level log data. I keeps a track of
  all [kernel](The_kernel.md) processes. It is invaluable when tracing the source
  of problems and errors that may arise on the system level. It keeps a track of
  all kernal processes.

  ![](/img/journald.png)

  ## `journalctl`

  We use `journalctl` to access the logs. The command by itself outputs the entire
  log which will be huge and hard to scroll through. We can refine the results
  with modifiers.

  ### View logs for a specific process with pid

  ```bash
  journalctl _PID=1234
  ```

  ### View logs for a specific time period

  This can be really helpful since you can bracket the most recent events which
  will be more memorable.

  ```bash
  journalctl -S -1h
  ```

  ### View logs for a specfic systemd unit

  ```bash
  journalctl -u [unit_name] -e
  ```

  ### View boot logs

  ```bash
  journalctl -b
  ```

  #### Identify specific boot

  ```bash
  journalctl --list-boots

  ```

  ### List only kernel entries to the journal

  ```bash
  journalctl -k

  ```


path: zk/jq.md
sortable_path: zkjq.md
title: jq
lead: ## Remove property
checksum: 676854d84ae30e105cfd98da7b65640c36c42493225fcdd94a44f13d3be84d41
created: 2024-03-30 09:03:22.101647543+00:00
modified: 2024-06-16 17:13:44.342347019+00:00
metadata: {"tags":["json","shell"]}
body:
  ## Remove property

  Remove property from a JSON array of objects:

  ```json
  {
    "member_inputs": [
      {
        "name": "Thomas",
        "input_type": "select"
      },
      {
        "name": "Martha",
        "input_type": "text"
      }
    ]
  }
  ```

  ```sh
  jq '.member_details |= map(del(.input_type))' memberDetails.json
  ```

  > Add '-i' to modify the source file directly (in-place)

  > Multiple properties can be deleted simply by chaining,
  > e.g.`(del(.input_type, .another_property))`

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

  # jq

  ## Remove property

  Remove property from a JSON array of objects:

  ```json
  {
    "member_inputs": [
      {
        "name": "Thomas",
        "input_type": "select"
      },
      {
        "name": "Martha",
        "input_type": "text"
      }
    ]
  }
  ```

  ```sh
  jq '.member_details |= map(del(.input_type))' memberDetails.json
  ```

  > Add '-i' to modify the source file directly (in-place)

  > Multiple properties can be deleted simply by chaining,
  > e.g.`(del(.input_type, .another_property))`


path: zk/python_advent_learnings.md
sortable_path: zkpython_advent_learnings.md
title: Python advent learnings
lead: ### Construct paths without hard-coding absolute path
checksum: 41e623fc64d7bdeedbc4cb74740ba94f0d812a86c637bec43edfdfb62f90f6b5
created: 2024-03-30 09:03:22.147095316+00:00
modified: 2024-03-27 10:45:52.510192133+00:00
metadata: {}
body:
  ### Construct paths without hard-coding absolute path

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

  ```

  ### Read file by line and store in variable

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

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


  puzzle_input = getPuzzleInput(puzzle_input_path)

  ```

  ### Conditional tests for members of arrays

  Check that all elements are greater than zero:

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

  Check if any element is less than 0:

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

  ### Check for substring:

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

  ### Control flow in loop

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

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

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

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

  ### Multiple loop in list comprehension

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

raw_content:
  # Python advent learnings

  ### Construct paths without hard-coding absolute path

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

  ```

  ### Read file by line and store in variable

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

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


  puzzle_input = getPuzzleInput(puzzle_input_path)

  ```

  ### Conditional tests for members of arrays

  Check that all elements are greater than zero:

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

  Check if any element is less than 0:

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

  ### Check for substring:

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

  ### Control flow in loop

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

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

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

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

  ### Multiple loop in list comprehension

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


path: zk/systemd.md
sortable_path: zksystemd.md
title: systemd
checksum: d49ea781434a68ed07dee06e34d8c820c7a529fd8d33e46835c65c6a2a542718
created: 2024-03-30 09:03:22.152461124+00:00
modified: 2024-06-15 09:43:23.547978531+00:00
metadata: {"tags":["systems-programming","Linux","procedural","systemd"]}
lead:
  Once the [boot process](Boot_process.md) has completed and the bootloader has
  located the kernel and injected it into memory the first user space program
  runs: `init` (for _initialisation_). `init` is a [daemon](Daemons.md) process
  that continues running until shutdown and is responsible for starting all the
  processes that are prerequisites for user space. For example: network
  connections, disk access, user logins etc. `init` is the parent of all
  processes: PID1. Whilst it does a lot of its work in quick succession at boot
  time it is not limited to the this stage of the lifescycle but runs continuously
  in reponse to new user events.

body:
  Once the [boot process](Boot_process.md) has completed and the bootloader has
  located the kernel and injected it into memory the first user space program
  runs: `init` (for _initialisation_). `init` is a [daemon](Daemons.md) process
  that continues running until shutdown and is responsible for starting all the
  processes that are prerequisites for user space. For example: network
  connections, disk access, user logins etc. `init` is the parent of all
  processes: PID1. Whilst it does a lot of its work in quick succession at boot
  time it is not limited to the this stage of the lifescycle but runs continuously
  in reponse to new user events.

  On Linux systems `systemd` is used to implement `init`.

  `systemd` is directly accessible from user space and provides a straightforward
  way to enable/disable, start/stop system level processes

  > `systemd` can track individual service daemons after they start, and group
  > together multiple processes associated with a service, giving you more power
  > and insight into exactly what is running on the system _How Linux Works: Third
  > Edition_, Brian Ward 2021

  ## How systemd works

  ### Goal-directed units

  `systemd` works on the basis of _goals_. Each goal is system task defined as a
  **unit**. A unit contains instructions and a specification of dependencies to
  other units.

  When activating a unit, `systemd` first activates the dependencies and then
  moves onto the details of the unit itself. `init` as implemented by `systemd`
  does not follow a rigid sequence every time, initialising units in the same
  sequence and waiting for one to complete before starting another. Instead it
  activates units whenever they are ready. This, its parallelized nature, is one
  of the main advantages over previous programs that managed the `init` sequence
  on Linux (such as for example System V);

  ### Unit types

  Units are organised into **unit types**. The main types that run at boot time
  are as follows:

  - service units (`.service`)
    - control service daemons
  - socket units (`.socket`)
    - handle incoming network connection request locations
  - device units (`.device`)
    - disks and other devices
  - mount units (`.mount`)
    - handle the attachment of filesystems to the system
  - target units
    - control other units by organising them into groups

  For example, at boot, a target unit called `default.target` groups together a
  number of service and mount units as dependencies. These then run in a
  graph-like dependency structure where a unit that comes late in the boot process
  can depend on several previous units making earlier branches of a dependency
  tree join back together.

  ## systemd configuration files

  Units are managed via `systemd` configuration files.

  ### Configuration file locations

  System level `systemd` config files are located in the _system unit directory_
  at `/usr/lib/systemd/system`. You shouldn't change or manipulate these files or
  attempt to add new config files here since they will be overwritten by the
  system.

  ![](/img/systemd-global-files.png) _`systemd` global unit files_

  Local definitions that relate to the specific user and where the user herself
  can define units are located in the _system configuration_ directory:
  `/etc/systemd/system`.

  ![](/img/systemd-local-files.png)

  _`systemd` local unit files, specific to the currently logged-in user_

  ### Example files

  Below is the systemd service file for the creation of UUIDs:

  ```plain
  [Unit]
  Description=Daemon for generating UUIDs
  Documentation=man:uuidd(8)
  Requires=uuidd.socket

  [Service]
  ExecStart=/usr/sbin/uuidd --socket-activation
  Restart=no
  User=uuidd
  Group=uuidd
  ProtectSystem=strict
  ProtectHome=yes
  PrivateDevices=yes
  PrivateUsers=yes
  ProtectKernelTunables=yes
  ProtectKernelModules=yes
  ProtectControlGroups=yes
  MemoryDenyWriteExecute=yes
  ReadWritePaths=/var/lib/libuuid/
  SystemCallFilter=@default @file-system @basic-io @system-service @signal @io-event @network-io

  [Install]
  Also=uuidd.socket
  ```

  - The `Unit` section provides metadata about the unit including which `systemd`
    dependencies it has
  - `Service` constitutes the main specification for the unit
  - `Install` is the call to set the dependencies running before the `Service`
    functions are accessible.

  ## systemd operations: systemctl

  The `systemctl` command is the chief way of interacting with `systemd`. You use
  it to activate and deactivate services, list their status, reload the
  configuration and so.

  ### View the dependency graph

  `systemctl status` by itself will print a long list of units grouped by their
  dependency relations. It will also provide some metadata about the current
  systemd boot context.

  ### Viewing active units

  Below I have listed the running units pertaining to bluetooth:

  ```
  $ systemctl list-units | grep bluetooth
   sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0-hci0:3585.device                                   loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0/hci0:3585
    sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0.device                                             loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0
    sys-subsystem-bluetooth-devices-hci0.device                                                                                    loaded active plugged   /sys/subsystem/bluetooth/devices/hci0
    sys-subsystem-bluetooth-devices-hci0:3585.device                                                                               loaded active plugged   /sys/subsystem/bluetooth/devices/hci0:3585
    bluetooth.service                                                                                                              loaded active running   Bluetooth service
    bluetooth.target                                                                                                               loaded active active    Bluetooth Support
  ```

  ### List jobs

  Requests to activate, reactivate and restart units are called **jobs** in
  `systemd`. They can be thought of as unit state changes. Current jobs can be
  listed with `systemctl list-jobs`.

  This will most likely return `No jobs running` if the computer has been running
  for a while. Most jobs execute at boot.

  ### Enable/disable, start/stop units

  If a unit has dependencies it is necessary to _enable_ it before starting it.
  This installs the dependencies.

  ```bash
  systemctl enable mongodb.service
  Created symlink /etc/systemd/system/multi-user.target.wants/mongodb.service → /usr/lib/systemd/system/mongodb.service.
  ```

  Then we can start:

  ```
  systemctl start mongodb.service
  ```

  To stop the service:

  ```
  systemctl stop mongodb.service
  ```

  After this we should disable it, in order to remove any symbolic links it has
  created on the system as part of the install process:

  ```bash
  systemctl disable mongodb.service
  Removed "/etc/systemd/system/multi-user.target.wants/mongodb.service".
  ```

  ## Why use systemd over cron ?

  https://mark.stosberg.com/2016-08-26-rsnapshot-and-systemd/

raw_content:
  ---
  tags:
    - systems-programming
    - Linux
    - procedural
    - systemd
  ---

  # systemd

  Once the [boot process](Boot_process.md) has completed and the bootloader has
  located the kernel and injected it into memory the first user space program
  runs: `init` (for _initialisation_). `init` is a [daemon](Daemons.md) process
  that continues running until shutdown and is responsible for starting all the
  processes that are prerequisites for user space. For example: network
  connections, disk access, user logins etc. `init` is the parent of all
  processes: PID1. Whilst it does a lot of its work in quick succession at boot
  time it is not limited to the this stage of the lifescycle but runs continuously
  in reponse to new user events.

  On Linux systems `systemd` is used to implement `init`.

  `systemd` is directly accessible from user space and provides a straightforward
  way to enable/disable, start/stop system level processes

  > `systemd` can track individual service daemons after they start, and group
  > together multiple processes associated with a service, giving you more power
  > and insight into exactly what is running on the system _How Linux Works: Third
  > Edition_, Brian Ward 2021

  ## How systemd works

  ### Goal-directed units

  `systemd` works on the basis of _goals_. Each goal is system task defined as a
  **unit**. A unit contains instructions and a specification of dependencies to
  other units.

  When activating a unit, `systemd` first activates the dependencies and then
  moves onto the details of the unit itself. `init` as implemented by `systemd`
  does not follow a rigid sequence every time, initialising units in the same
  sequence and waiting for one to complete before starting another. Instead it
  activates units whenever they are ready. This, its parallelized nature, is one
  of the main advantages over previous programs that managed the `init` sequence
  on Linux (such as for example System V);

  ### Unit types

  Units are organised into **unit types**. The main types that run at boot time
  are as follows:

  - service units (`.service`)
    - control service daemons
  - socket units (`.socket`)
    - handle incoming network connection request locations
  - device units (`.device`)
    - disks and other devices
  - mount units (`.mount`)
    - handle the attachment of filesystems to the system
  - target units
    - control other units by organising them into groups

  For example, at boot, a target unit called `default.target` groups together a
  number of service and mount units as dependencies. These then run in a
  graph-like dependency structure where a unit that comes late in the boot process
  can depend on several previous units making earlier branches of a dependency
  tree join back together.

  ## systemd configuration files

  Units are managed via `systemd` configuration files.

  ### Configuration file locations

  System level `systemd` config files are located in the _system unit directory_
  at `/usr/lib/systemd/system`. You shouldn't change or manipulate these files or
  attempt to add new config files here since they will be overwritten by the
  system.

  ![](/img/systemd-global-files.png) _`systemd` global unit files_

  Local definitions that relate to the specific user and where the user herself
  can define units are located in the _system configuration_ directory:
  `/etc/systemd/system`.

  ![](/img/systemd-local-files.png)

  _`systemd` local unit files, specific to the currently logged-in user_

  ### Example files

  Below is the systemd service file for the creation of UUIDs:

  ```plain
  [Unit]
  Description=Daemon for generating UUIDs
  Documentation=man:uuidd(8)
  Requires=uuidd.socket

  [Service]
  ExecStart=/usr/sbin/uuidd --socket-activation
  Restart=no
  User=uuidd
  Group=uuidd
  ProtectSystem=strict
  ProtectHome=yes
  PrivateDevices=yes
  PrivateUsers=yes
  ProtectKernelTunables=yes
  ProtectKernelModules=yes
  ProtectControlGroups=yes
  MemoryDenyWriteExecute=yes
  ReadWritePaths=/var/lib/libuuid/
  SystemCallFilter=@default @file-system @basic-io @system-service @signal @io-event @network-io

  [Install]
  Also=uuidd.socket
  ```

  - The `Unit` section provides metadata about the unit including which `systemd`
    dependencies it has
  - `Service` constitutes the main specification for the unit
  - `Install` is the call to set the dependencies running before the `Service`
    functions are accessible.

  ## systemd operations: systemctl

  The `systemctl` command is the chief way of interacting with `systemd`. You use
  it to activate and deactivate services, list their status, reload the
  configuration and so.

  ### View the dependency graph

  `systemctl status` by itself will print a long list of units grouped by their
  dependency relations. It will also provide some metadata about the current
  systemd boot context.

  ### Viewing active units

  Below I have listed the running units pertaining to bluetooth:

  ```
  $ systemctl list-units | grep bluetooth
   sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0-hci0:3585.device                                   loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0/hci0:3585
    sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d10-3\x2d10:1.0-bluetooth-hci0.device                                             loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0
    sys-subsystem-bluetooth-devices-hci0.device                                                                                    loaded active plugged   /sys/subsystem/bluetooth/devices/hci0
    sys-subsystem-bluetooth-devices-hci0:3585.device                                                                               loaded active plugged   /sys/subsystem/bluetooth/devices/hci0:3585
    bluetooth.service                                                                                                              loaded active running   Bluetooth service
    bluetooth.target                                                                                                               loaded active active    Bluetooth Support
  ```

  ### List jobs

  Requests to activate, reactivate and restart units are called **jobs** in
  `systemd`. They can be thought of as unit state changes. Current jobs can be
  listed with `systemctl list-jobs`.

  This will most likely return `No jobs running` if the computer has been running
  for a while. Most jobs execute at boot.

  ### Enable/disable, start/stop units

  If a unit has dependencies it is necessary to _enable_ it before starting it.
  This installs the dependencies.

  ```bash
  systemctl enable mongodb.service
  Created symlink /etc/systemd/system/multi-user.target.wants/mongodb.service → /usr/lib/systemd/system/mongodb.service.
  ```

  Then we can start:

  ```
  systemctl start mongodb.service
  ```

  To stop the service:

  ```
  systemctl stop mongodb.service
  ```

  After this we should disable it, in order to remove any symbolic links it has
  created on the system as part of the install process:

  ```bash
  systemctl disable mongodb.service
  Removed "/etc/systemd/system/multi-user.target.wants/mongodb.service".
  ```

  ## Why use systemd over cron ?

  https://mark.stosberg.com/2016-08-26-rsnapshot-and-systemd/


path: zk/systemd_status.md
sortable_path: zksystemd_status.md
title: systemd status
lead: # Get status of a specific unit
checksum: f2ec1eb5d619ecd6270fe8ede5fc2088b176c6af31e805c2ea6bfe25f5bb717d
created: 2024-03-30 09:03:22.167794749+00:00
modified: 2024-06-15 09:42:04.726250922+00:00
body:
  # Get status of a specific unit

  Here I have requested the status of the currently running `mongodb` unit:

  ```
  $ systemctl status mongod
  mongodb.service - MongoDB Database Server
       Loaded: loaded (/usr/lib/systemd/system/mongodb.service; enabled; preset: disabled)
       Active: active (running) since Wed 2022-08-17 07:25:27 BST; 24h ago
         Docs: https://docs.mongodb.org/manual
     Main PID: 931 (mongod)
       Memory: 304.1M
          CPU: 2min 18.630s
       CGroup: /system.slice/mongodb.service
               └─931 /usr/bin/mongod --config /etc/mongodb.conf
  Aug 17 07:25:27 archbish systemd[1]: Started MongoDB Database Server.****
  ```

  In addition to the core info it tells us the unit type. In this case it is a
  service.

  We can also view the journal entry for the given unit. This provides you with
  its diagnostic log messages:

  ```
  journalctl --unit=mongodb.service
  - Boot b9565dfe8aca4d069143209b3aa84d8e --
  Aug 05 18:31:30 archbish systemd[1]: Started MongoDB Database Server.
  Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Consumed 3min 17.598s CPU time.
  -- Boot 01922f84c3bd4b3a8f11824cf05f7320 --
  Aug 07 11:58:09 archbish systemd[1]: Started MongoDB Database Server.
  Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Consumed 5min 28.760s CPU time.
  -- Boot e52b735e115c43bdad8c00462aaff395 --
  Aug 10 13:13:22 archbish systemd[1]: Started MongoDB Database Server.
  Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Consumed 2min 16.629s CPU time.
  ```

  Each entry is organised around specific boots.

raw_content:
  ---
  id: v5f6xkdv
  title: systemd status
  tags:
    - systemd
    - systems-programming
    - Linux
    - procedural
  created: Thursday, February 29, 2024 | 18:19
  ---

  # Get status of a specific unit

  Here I have requested the status of the currently running `mongodb` unit:

  ```
  $ systemctl status mongod
  mongodb.service - MongoDB Database Server
       Loaded: loaded (/usr/lib/systemd/system/mongodb.service; enabled; preset: disabled)
       Active: active (running) since Wed 2022-08-17 07:25:27 BST; 24h ago
         Docs: https://docs.mongodb.org/manual
     Main PID: 931 (mongod)
       Memory: 304.1M
          CPU: 2min 18.630s
       CGroup: /system.slice/mongodb.service
               └─931 /usr/bin/mongod --config /etc/mongodb.conf
  Aug 17 07:25:27 archbish systemd[1]: Started MongoDB Database Server.****
  ```

  In addition to the core info it tells us the unit type. In this case it is a
  service.

  We can also view the journal entry for the given unit. This provides you with
  its diagnostic log messages:

  ```
  journalctl --unit=mongodb.service
  - Boot b9565dfe8aca4d069143209b3aa84d8e --
  Aug 05 18:31:30 archbish systemd[1]: Started MongoDB Database Server.
  Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 06 14:27:33 archbish systemd[1]: mongodb.service: Consumed 3min 17.598s CPU time.
  -- Boot 01922f84c3bd4b3a8f11824cf05f7320 --
  Aug 07 11:58:09 archbish systemd[1]: Started MongoDB Database Server.
  Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 08 14:43:01 archbish systemd[1]: mongodb.service: Consumed 5min 28.760s CPU time.
  -- Boot e52b735e115c43bdad8c00462aaff395 --
  Aug 10 13:13:22 archbish systemd[1]: Started MongoDB Database Server.
  Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Deactivated successfully.
  Aug 11 07:46:40 archbish systemd[1]: mongodb.service: Consumed 2min 16.629s CPU time.
  ```

  Each entry is organised around specific boots.

metadata:
  {"created":"Thursday, February 29, 2024 | 18:19","id":"v5f6xkdv","tags":["systemd","systems-programming","Linux","procedural"],"title":"systemd status"}


path: zk/v8.md
sortable_path: zkv8.md
title: v8
checksum: b10a7303881a96d28e9623865c847d3ad3c39bf9056b9d8c1820f7236db2b385
created: 2024-03-30 09:03:22.234796202+00:00
modified: 2024-06-15 09:50:49.133680044+00:00
metadata: {"tags":["node-js"]}
lead:
  The v8 module is useful for providing information about the resource-usage of
  your Node.js apps, such as memory usage and capacity.

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

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

  # v8

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


path: zk/Docker_CLI.md
sortable_path: zkDocker_CLI.md
title: Docker_CLI
lead: # Docker_CLI
checksum: d53b218fa9b08d4a661007985dc7ef4b67cd04f31860b13f88b1a9d3f71a9d34
created: 2024-03-30 14:42:27.76745933+00:00
modified: 2024-06-16 17:05:29.100841947+00:00
metadata: {"created":"Saturday, March 30, 2024","id":"6g54","tags":["docker","shell"],"title":"Docker_CLI"}
body:
  # Docker_CLI

  ```sh
  # List images
  docker image ls

  # List container
  docker container ls

  # Remove container
  docker rm container-name

  # Remove image

  docker rmi image_name:version

  ```

raw_content:
  ---
  id: 6g54
  title: Docker_CLI
  tags:
    - docker
    - shell
  created: Saturday, March 30, 2024
  ---

  # Docker_CLI

  ```sh
  # List images
  docker image ls

  # List container
  docker container ls

  # Remove container
  docker rm container-name

  # Remove image

  docker rmi image_name:version

  ```


path: zk/Stack_memory.md
sortable_path: zkStack_memory.md
title: Stack_memory
lead: # Stack memory
checksum: 9ea1d4406f69d2cc83a433d862b3314b6ea9830bb94aa92c4cf800e465cac391
created: 2024-04-16 06:46:27.952023721+00:00
modified: 2024-04-20 12:40:16.05327467+00:00
metadata: {"created":"Tuesday, April 16, 2024","id":"1fig","tags":["memory"],"title":"Stack_memory"}
body:
  # Stack memory

  ## Summary

  - Along with [[Heap_memory|heap memory]] heap memory, programs make use of
    _stack memory_ during runtime.
  - [ ]
  - Best suited for small-sized singular values that are temporary/ephemeral
    rather than large or complex data types that need to persist for a longer
    time.

  - Specifically used to keep track of memory used during function executions
    within a given scope: control flow, local variables, returned value.

  - Uses a LIFO data-structure

  Similarly to the [[Stacks|stack data structure]], it works on the basis of LIFO:
  the last item put on the stack is the first item to be withdrawn.

  Note, this doesn't mean that the data at the memory addresses that comprise the
  stack can _only_ be accessed in a LIFO manner. Any item currently on the stack
  can be accessed (be read or modified) at any time. LIFO applies when it is is
  time to clear memory from the stack: the most recent addition is cleared first
  from the top down.

  ### Stack pointer

  A **stack pointer** is used to manage the items in the stack. This value is
  stored in a [[CPU_architecture#registers|register]] and its value is the memory
  address of the item currently on the top of the stack. Note: _not_ the value
  itself, the _address_ of the value.

  When a new value is added to the top of the stack, the pointer's value is
  adjusted to increase the size of the stack and make room for the new value. So
  this will be a new memory address for the latest item. When an item is removed,
  the reverse happens. The previously top address is cleared and the pointer
  points to the new top item.

  ## Threads

  For every thread that a program spawns, it gets its own stack or "stack frame".
  Stack memory within the thread can only be accessed by processes within that
  thread which is what makes it well suited for managing scoped function memory.

  ### Role in program execution

  1. Function call management: a stack records the key information pertaining to
     the execution of a function: parameters, local variables, the location of the
     address for the returned value.

  2. Local variable storage: storing the variables local to a function's scope and
     removing them once the function returns, avoiding
     [[Memory_leaks|memory leaks]]

  3. Control flow: record from where a function is called and where its return
     value should be stored, meaning the right value is always returned no matter
     how nested it is.

  4. Recursion: individuating each call of a function that calls itself and its
     given step to avoid infinite loops

  ## Related notes

raw_content:
  ---
  id: 1fig
  title: Stack_memory
  tags: [memory]
  created: Tuesday, April 16, 2024
  ---

  # Stack memory

  ## Summary

  - Along with [[Heap_memory|heap memory]] heap memory, programs make use of
    _stack memory_ during runtime.
  - [ ]
  - Best suited for small-sized singular values that are temporary/ephemeral
    rather than large or complex data types that need to persist for a longer
    time.

  - Specifically used to keep track of memory used during function executions
    within a given scope: control flow, local variables, returned value.

  - Uses a LIFO data-structure

  Similarly to the [[Stacks|stack data structure]], it works on the basis of LIFO:
  the last item put on the stack is the first item to be withdrawn.

  Note, this doesn't mean that the data at the memory addresses that comprise the
  stack can _only_ be accessed in a LIFO manner. Any item currently on the stack
  can be accessed (be read or modified) at any time. LIFO applies when it is is
  time to clear memory from the stack: the most recent addition is cleared first
  from the top down.

  ### Stack pointer

  A **stack pointer** is used to manage the items in the stack. This value is
  stored in a [[CPU_architecture#registers|register]] and its value is the memory
  address of the item currently on the top of the stack. Note: _not_ the value
  itself, the _address_ of the value.

  When a new value is added to the top of the stack, the pointer's value is
  adjusted to increase the size of the stack and make room for the new value. So
  this will be a new memory address for the latest item. When an item is removed,
  the reverse happens. The previously top address is cleared and the pointer
  points to the new top item.

  ## Threads

  For every thread that a program spawns, it gets its own stack or "stack frame".
  Stack memory within the thread can only be accessed by processes within that
  thread which is what makes it well suited for managing scoped function memory.

  ### Role in program execution

  1. Function call management: a stack records the key information pertaining to
     the execution of a function: parameters, local variables, the location of the
     address for the returned value.

  2. Local variable storage: storing the variables local to a function's scope and
     removing them once the function returns, avoiding
     [[Memory_leaks|memory leaks]]

  3. Control flow: record from where a function is called and where its return
     value should be stored, meaning the right value is always returned no matter
     how nested it is.

  4. Recursion: individuating each call of a function that calls itself and its
     given step to avoid infinite loops

  ## Related notes


path: zk/Heap_memory.md
sortable_path: zkHeap_memory.md
title: Heap_memory
lead: # Heap memory
checksum: e3c8291a7b7a967ad06d00498dc3ac2452b15cfac3719ddb91f8b867d740c0bb
created: 2024-04-20 12:14:59.272099511+00:00
modified: 2024-04-20 13:42:01.847818114+00:00
metadata: {"created":"Saturday, April 20, 2024","id":"18bl","tags":["memory","C"],"title":"Heap_memory"}
body:
  # Heap memory

  Along with [[Stack_memory|Stack memory]], programs make use of _heap memory_
  during runtime.

  Heap memory does not use a standardised data structure and can be accessed from
  any point within the program.

  Whereas stack memory with it's LIFO structure has memory management built-in
  when programs allocate memory from the heap they must manually deallocate it
  when it is no longer required. This process of "freeing memory" is known as
  _garbage collection_. In a language like C, this is the explicit concern of the
  programmer and is not abstracted away. Failure to properly manage garbage
  collection is what causes [[Memory_leaks]].

  Heap memory is used in combination with the stack since a given heap memory
  allocation address is stored as a stack variable during runtime. It points to
  the heap memory address whilst not being that memory itself.

  Here is an example of managing heap memory allocation in C:

  ```c
  void * data;
  data = malloc(512)
  ```

  The first line assigns a special _pointer_ variable (indicated by `void *`
  rather than `int` or `str`) . This is a variable only holds a memory address.
  The `malloc` method requests 512 bytes that it wants to assign to the `data`
  variable. It will return the address of the first byte in the newly allocated
  memory. `data` will then refer to the address on the stack that holds the
  address allocation on the heap.

  ## Related notes

raw_content:
  ---
  id: 18bl
  title: Heap_memory
  tags: [memory, C]
  created: Saturday, April 20, 2024
  ---

  # Heap memory

  Along with [[Stack_memory|Stack memory]], programs make use of _heap memory_
  during runtime.

  Heap memory does not use a standardised data structure and can be accessed from
  any point within the program.

  Whereas stack memory with it's LIFO structure has memory management built-in
  when programs allocate memory from the heap they must manually deallocate it
  when it is no longer required. This process of "freeing memory" is known as
  _garbage collection_. In a language like C, this is the explicit concern of the
  programmer and is not abstracted away. Failure to properly manage garbage
  collection is what causes [[Memory_leaks]].

  Heap memory is used in combination with the stack since a given heap memory
  allocation address is stored as a stack variable during runtime. It points to
  the heap memory address whilst not being that memory itself.

  Here is an example of managing heap memory allocation in C:

  ```c
  void * data;
  data = malloc(512)
  ```

  The first line assigns a special _pointer_ variable (indicated by `void *`
  rather than `int` or `str`) . This is a variable only holds a memory address.
  The `malloc` method requests 512 bytes that it wants to assign to the `data`
  variable. It will return the address of the first byte in the newly allocated
  memory. `data` will then refer to the address on the stack that holds the
  address allocation on the heap.

  ## Related notes


path: zk/Bitwise_operators.md
sortable_path: zkBitwise_operators.md
title: Bitwise_operators
lead: # Bitwise operators
checksum: de0c5734330e9f4351e0dd66dcc6527fe46b016e2ab7622f79349aa8723bcf57
created: 2024-04-20 13:49:57.582757199+00:00
modified: 2024-04-20 14:25:08.308261193+00:00
metadata: {"created":"Saturday, April 20, 2024","id":"t127","tags":["binary"],"title":"Bitwise_operators"}
body:
  # Bitwise operators

  In addition to mathematical, logical and comparison operators, there are
  _bitwise operators_. These operators execute conditions based on the actual bits
  of a value rather than the values that the bits are encoded to represent.

  Bitwise operators are typically represented with single characters of existing
  operators, e.g. `&` instead of `&&`:

  | Bitwise operation | Operator      |
  | ----------------- | ------------- |
  | AND               | `&`           |
  | OR                | (single pipe) |
  | NOT               | `~`           |

  An example of using the `&` operator:

  ```py
  x = 5
  y = 3
  a = x & y
  b = x | y
  ```

  The value of `a` will be 1. The reason is we are looking at the bit values of
  `x` and `y` and then applying Boolean AND to each bit:

  ```
  x = 5 = 0101
  y = 3 = 0011
  a = 1 = 0001
  ```

  Working from right to left for each column:

  - true and true = true
  - false and true = false
  - true and false = false
  - false and false = false

  This leaves us with 0001 which is equal to 1 in binary and denary.

  For the case of bitwise OR we get 7 as the result of `x | y`:

  ```
  x = 5 = 0101
  y = 3 = 0011
  b = 7 = 0111
  ```

  - true or true = true
  - false or true = true
  - true or false = true
  - false or false = true

  This leaves us with 0111 which is equal to 7 in denary.

  ## Why use them?

  Bitwise operations are more of a hallmark of lower-level programming. As bit
  operations are the fastest and lowest level of computation, being able to
  directly access and operate on bits within a programming language can be
  beneficial when efficiency and speed of execution is a factor or when memory is
  constrained.

  ## Related notes

raw_content:
  ---
  id: t127
  title: Bitwise_operators
  tags: [binary]
  created: Saturday, April 20, 2024
  ---

  # Bitwise operators

  In addition to mathematical, logical and comparison operators, there are
  _bitwise operators_. These operators execute conditions based on the actual bits
  of a value rather than the values that the bits are encoded to represent.

  Bitwise operators are typically represented with single characters of existing
  operators, e.g. `&` instead of `&&`:

  | Bitwise operation | Operator      |
  | ----------------- | ------------- |
  | AND               | `&`           |
  | OR                | (single pipe) |
  | NOT               | `~`           |

  An example of using the `&` operator:

  ```py
  x = 5
  y = 3
  a = x & y
  b = x | y
  ```

  The value of `a` will be 1. The reason is we are looking at the bit values of
  `x` and `y` and then applying Boolean AND to each bit:

  ```
  x = 5 = 0101
  y = 3 = 0011
  a = 1 = 0001
  ```

  Working from right to left for each column:

  - true and true = true
  - false and true = false
  - true and false = false
  - false and false = false

  This leaves us with 0001 which is equal to 1 in binary and denary.

  For the case of bitwise OR we get 7 as the result of `x | y`:

  ```
  x = 5 = 0101
  y = 3 = 0011
  b = 7 = 0111
  ```

  - true or true = true
  - false or true = true
  - true or false = true
  - false or false = true

  This leaves us with 0111 which is equal to 7 in denary.

  ## Why use them?

  Bitwise operations are more of a hallmark of lower-level programming. As bit
  operations are the fastest and lowest level of computation, being able to
  directly access and operate on bits within a programming language can be
  beneficial when efficiency and speed of execution is a factor or when memory is
  constrained.

  ## Related notes


path: zk/NodeJS_scripts.md
sortable_path: zkNodeJS_scripts.md
title: NodeJS_scripts
lead: # NodeJS_scripts
checksum: 7f543a01a82b789f7dbb6cdf76cb210ae0e4522439bd842a5694761bb0943872
created: 2024-04-26 09:50:22.490916912+00:00
modified: 2024-04-28 10:34:57.917110341+00:00
metadata: {"created":"Friday, April 26, 2024","id":5043,"tags":["node-js"],"title":"NodeJS_scripts"}
body:
  # NodeJS_scripts

  If we want to use NodeJS as a scripting language without going to the trouble of
  setting up an NPM-based development environment, we can use the following
  architecture.

  ```js
  #!/usr/bin/env node

  const process = require("process");

  const actualScript = (firstParam, secondParam) => {
    // Do something
  };

  if (require.main === module) {
    const [, param1, param2] = process.argv;
    actualScript(param1, param2).catch(console.error);
  }
  ```

  Basically we have a function that contains the main actions of the script. This
  is then invoked within `main` in the manner of a Bash or
  ![Python script](./Single_file_Python_scripts.md)

  This obviously requires the Node binary to be in your path and the script must
  be run with executable privileges.

  If you use any module not in the Node core, you will need to have this installed
  globally for it to work. (There are
  [ways around this](https://thom4.net/2014/self-contained-node-scripts/) for Node
  scripts you publish but for personal scripts this doesn't matter.)

  ## `require.main`

  This construction checks that the script is being directy invoked via the 'node'
  command in the terminal rather than called by another module.

  This is equivalent to the [following construct]() in Python:

  ```py
  if __name__ == "__main__":
  ```

raw_content:
  ---
  id: 5043
  title: NodeJS_scripts
  tags: [node-js]
  created: Friday, April 26, 2024
  ---

  # NodeJS_scripts

  If we want to use NodeJS as a scripting language without going to the trouble of
  setting up an NPM-based development environment, we can use the following
  architecture.

  ```js
  #!/usr/bin/env node

  const process = require("process");

  const actualScript = (firstParam, secondParam) => {
    // Do something
  };

  if (require.main === module) {
    const [, param1, param2] = process.argv;
    actualScript(param1, param2).catch(console.error);
  }
  ```

  Basically we have a function that contains the main actions of the script. This
  is then invoked within `main` in the manner of a Bash or
  ![Python script](./Single_file_Python_scripts.md)

  This obviously requires the Node binary to be in your path and the script must
  be run with executable privileges.

  If you use any module not in the Node core, you will need to have this installed
  globally for it to work. (There are
  [ways around this](https://thom4.net/2014/self-contained-node-scripts/) for Node
  scripts you publish but for personal scripts this doesn't matter.)

  ## `require.main`

  This construction checks that the script is being directy invoked via the 'node'
  command in the terminal rather than called by another module.

  This is equivalent to the [following construct]() in Python:

  ```py
  if __name__ == "__main__":
  ```


path: zk/Single_file_Python_scripts.md
sortable_path: zkSingle_file_Python_scripts.md
title: Single_file_Python_scripts
lead: # Single_file_Python_scripts
checksum: 6145bde1593264784876cfb088585d22a6aaaf70fadb477df93bec755ee419a3
created: 2024-04-26 09:58:57.238585351+00:00
modified: 2024-04-28 10:51:45.411832459+00:00
metadata: {"created":"Friday, April 26, 2024","id":"atzw","tags":[],"title":"Single_file_Python_scripts"}
body:
  # Single_file_Python_scripts

  ## Basic architecture

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

  import sys

  if __name__ == "__main__":
      all_args = sys.argv
      specific_arg = sys.argv[0]
      # Main functionality...
  ```

  When you run a script (module) Python assigns the string `__main__` to the
  `__name__` attribute to the script that is being executed.

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`.

  Everything can go under the `__main__` conditional, or, for better readability,
  you can define a `main` function that is then invoked, e.g:

  ```py

  def main():
      # Do some stuff


  if __name__ == "__main__":
      main()

  ```

  ## Related notes

  ![Python modules and imports](./Python_modules_and_imports.md)

raw_content:
  ---
  id: atzw
  title: Single_file_Python_scripts
  tags: []
  created: Friday, April 26, 2024
  ---

  # Single_file_Python_scripts

  ## Basic architecture

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

  import sys

  if __name__ == "__main__":
      all_args = sys.argv
      specific_arg = sys.argv[0]
      # Main functionality...
  ```

  When you run a script (module) Python assigns the string `__main__` to the
  `__name__` attribute to the script that is being executed.

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`.

  Everything can go under the `__main__` conditional, or, for better readability,
  you can define a `main` function that is then invoked, e.g:

  ```py

  def main():
      # Do some stuff


  if __name__ == "__main__":
      main()

  ```

  ## Related notes

  ![Python modules and imports](./Python_modules_and_imports.md)


path: zk/Working_with_CSVs_in_Python.md
sortable_path: zkWorking_with_CSVs_in_Python.md
title: Working_with_CSVs_in_Python
lead: # Working_with_CSVs_in_Python
checksum: 9dd9c338f63f3d56c19fa7e30cc88d5665e984f99de28190efbe6f02e5dac060
created: 2024-04-28 11:17:03.295837625+00:00
modified: 2024-04-28 16:09:21.572769207+00:00
body:
  # Working_with_CSVs_in_Python

  ## Core package

  ```py
  import csv
  ```

  ## Read and write to CSV

  ### Read

  Use standard Pythonic "read" syntax:

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

  ### Parse values

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

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

  Will return something like:

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

  Which we can individuate with:

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

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

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

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

  Say we have a CSV with the following headers:

  ```csv
  name, profession
  ```

  We can individuate thus:

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

  ### Write

  Use standard Pythonic "read" syntax:

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

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

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

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

raw_content:
  ---
  id: sgtn
  title: Working_with_CSVs_in_Python
  tags: [python, csv]
  created: Sunday, April 28, 2024
  ---

  # Working_with_CSVs_in_Python

  ## Core package

  ```py
  import csv
  ```

  ## Read and write to CSV

  ### Read

  Use standard Pythonic "read" syntax:

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

  ### Parse values

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

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

  Will return something like:

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

  Which we can individuate with:

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

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

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

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

  Say we have a CSV with the following headers:

  ```csv
  name, profession
  ```

  We can individuate thus:

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

  ### Write

  Use standard Pythonic "read" syntax:

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

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

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

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

metadata:
  {"created":"Sunday, April 28, 2024","id":"sgtn","tags":["python","csv"],"title":"Working_with_CSVs_in_Python"}


path: zk/Time_and_computers.md
sortable_path: zkTime_and_computers.md
title: Time_and_computers
lead: # Time and computers
checksum: 87767416ea6b2c08381c74cdda962a1553cc48b405f37fbaa2ef1fc722745479
created: 2024-04-28 16:09:38.744041761+00:00
modified: 2024-06-15 10:06:32.764361797+00:00
body:
  # Time and computers

  ## Epochs and Unix Time

  An epoch is a period of time identified by a starting point.

  The standard epoch for measuring against is known colloqially as "Unix Time":
  midnight on 1st January 1970. Unix time is the number of seconds that have
  elapsed since this point. This is the standard for Windows and most unix
  systems.

  For example midnight on 2nd January 1970 would be 86400 seconds since the epoch.
  The deduction is as follows:

  ```
  60 * 60 * 24 = 86400
  ```

  We are multiplpying the number of seconds in a minute by the number of minutes
  in an hour by the number of hours in a day.

  To represent times and dates before 1970, we use negative integers.

  ## UTC and time zones

  "Coordinated Universal Time" (UTC) is the time standard against which the
  world's timekeeping is synchronized. It is not itself a timezone, it is a
  transcendent standard that defines what time zones are.

  Time zones are defined relative to UTC, by their offset to this value.

  For example North America is behind UTC by five or six hours hence uses the
  notation UTC-5:00 or UTC-6:00.

  UTC is the successor to GMT of which there were variances necessitating a
  universal value. Despite this GMT is equal to UTC+00:00 so apart from when
  daylight saving is in effect in the UK, GMT = UTC.

  Depending on your locale, relative to UTC, you will get different outputs when
  you attempt to log Unix Time.

  Also daylight savings can impact on the outputs. For instance for half of the
  year, when DST applies, the UK is UTC+01:00.

  ## Examples in Python

  The following gives us the unix seconds in my current time zone (GMT DST):

  ```py
  import time
  print(time.time())
  # 1714322393.2929392
  ```

  If I want UTC, I can do:

  ```py
  import datetime
  print(datetime.datetime.utcnow().strftime('%s'))
  # '1714318952'
  ```

  We see clearly that they are not identical.

raw_content:
  ---
  id: l29u
  title: Time_and_computers
  tags:
    - unix
    - time
  created: Sunday, April 28, 2024
  ---

  # Time and computers

  ## Epochs and Unix Time

  An epoch is a period of time identified by a starting point.

  The standard epoch for measuring against is known colloqially as "Unix Time":
  midnight on 1st January 1970. Unix time is the number of seconds that have
  elapsed since this point. This is the standard for Windows and most unix
  systems.

  For example midnight on 2nd January 1970 would be 86400 seconds since the epoch.
  The deduction is as follows:

  ```
  60 * 60 * 24 = 86400
  ```

  We are multiplpying the number of seconds in a minute by the number of minutes
  in an hour by the number of hours in a day.

  To represent times and dates before 1970, we use negative integers.

  ## UTC and time zones

  "Coordinated Universal Time" (UTC) is the time standard against which the
  world's timekeeping is synchronized. It is not itself a timezone, it is a
  transcendent standard that defines what time zones are.

  Time zones are defined relative to UTC, by their offset to this value.

  For example North America is behind UTC by five or six hours hence uses the
  notation UTC-5:00 or UTC-6:00.

  UTC is the successor to GMT of which there were variances necessitating a
  universal value. Despite this GMT is equal to UTC+00:00 so apart from when
  daylight saving is in effect in the UK, GMT = UTC.

  Depending on your locale, relative to UTC, you will get different outputs when
  you attempt to log Unix Time.

  Also daylight savings can impact on the outputs. For instance for half of the
  year, when DST applies, the UK is UTC+01:00.

  ## Examples in Python

  The following gives us the unix seconds in my current time zone (GMT DST):

  ```py
  import time
  print(time.time())
  # 1714322393.2929392
  ```

  If I want UTC, I can do:

  ```py
  import datetime
  print(datetime.datetime.utcnow().strftime('%s'))
  # '1714318952'
  ```

  We see clearly that they are not identical.

metadata:
  {"created":"Sunday, April 28, 2024","id":"l29u","tags":["unix","time"],"title":"Time_and_computers"}


path: zk/Invoking_the_shell_in_Python.md
sortable_path: zkInvoking_the_shell_in_Python.md
title: Invoking_the_shell_in_Python
lead: # Invoking the shell_in_Python
checksum: b46d529813d2ecd507d9b69050e225ab2cbd7eabc54bd619f2d378973d0a897a
created: 2024-04-29 16:47:43.359796333+00:00
modified: 2024-06-18 06:42:59.697850247+00:00
body:
  # Invoking the shell_in_Python

  ```py
  import subprocess

  try:
      process = subprocess.run(
          ["ls", "-la"],
          shell=True,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE,
          text=True,
      )
      return process.stdout

  except subprocess.CalledProcessError as e:
          return e.stderr.strip()
  ```

raw_content:
  ---
  id: cfr4
  title: Invoking_the_shell_in_Python
  tags: [python, shell]
  created: Monday, April 29, 2024
  ---

  # Invoking the shell_in_Python

  ```py
  import subprocess

  try:
      process = subprocess.run(
          ["ls", "-la"],
          shell=True,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE,
          text=True,
      )
      return process.stdout

  except subprocess.CalledProcessError as e:
          return e.stderr.strip()
  ```

metadata:
  {"created":"Monday, April 29, 2024","id":"cfr4","tags":["python","shell"],"title":"Invoking_the_shell_in_Python"}


path: zk/Linux_disk_partitions.md
sortable_path: zkLinux_disk_partitions.md
title: Linux disk partitions
checksum: 73864c1fb6e564152cb3aaf302a8247e12a520c1a1e1d755db9d25d5611d14fa
created: 2024-05-06 12:16:39.739170407+00:00
modified: 2024-06-16 17:26:03.899469312+00:00
metadata: {"tags":["disks","Linux","procedural"]}
lead:
  A disk is divided up into partitions which are subsections of the overall disk.
  The kernel presents each partition as a [block device](Devices.md#Devices) as it
  would with an entire disk.

body:
  A disk is divided up into partitions which are subsections of the overall disk.
  The kernel presents each partition as a [block device](Devices.md#Devices) as it
  would with an entire disk.

  The disk dedicates a small part of its contents to a **partition table**: this
  defines the different partitions that comprise the total disk space.

  ## Viewing current partitions

  Whenever you install a Linux distribution on a real or virtual machine, you must
  partition the drive. There are three main tools to choose from: `parted`,
  `g(raphical)parted`, `fdisk`.

  For a top-level overview of your disks and their main partitions you can run
  `lsblk` (_list block devices_):

  ```bash
  $ lsblk

  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ├─sda1        8:1    0   200M  0 part
  └─sda2        8:2    0 465.4G  0 part /run/media/thomas/ganesh
  nvme0n1     259:0    0 476.9G  0 disk
  ├─nvme0n1p1 259:1    0   488M  0 part
  ├─nvme0n1p2 259:2    0  27.9G  0 part /
  └─nvme0n1p3 259:3    0 448.5G  0 part /home
  ```

  We can use `parted -l` to view the partition table for the current machine:

  ```bash
  Model: SKHynix_HFS512GDE9X081N (nvme)
  Disk /dev/nvme0n1: 512GB
  Sector size (logical/physical): 512B/512B
  Partition Table: gpt
  Disk Flags:

  Number  Start   End     Size    File system  Name  Flags
   1      1049kB  513MB   512MB   fat32              boot, esp
   2      513MB   30.5GB  30.0GB  ext4
   3      30.5GB  512GB   482GB   ext4
  ```

  We can use `fdisk -l` to get slightly more info:

  ```bash
  disk /dev/nvme0n1: 476.94 GiB, 512110190592 bytes, 1000215216 sectors
  Disk model: SKHynix_HFS512GDE9X081N
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 08175E77-CB9F-C34A-9032-DF29A3F8F0FE

  Device            Start        End   Sectors   Size Type
  /dev/nvme0n1p1     2048    1001471    999424   488M EFI System
  /dev/nvme0n1p2  1001472   59594751  58593280  27.9G Linux filesystem
  /dev/nvme0n1p3 59594752 1000214527 940619776 448.5G Linux filesystem
  ```

  ## Standard Linux partitions

  The two tools disclose that the main harddrive is `/dev/nvme0n1` (equivalent to
  `sda` on older machines running Linux) and it has the standard three partitions:

  - Boot partition (`/dev/nvme0n1p1`)
  - Root dir (`/dev/nvme0n1p2`)
  - Home dir (`/dev/nvme0n1p3`)

  ### Boot partition

  - Takes up the smallest amount of space
  - Contains the Linux kernel and the bootloader (GRUB, usually) and any other
    files required for booting.
  - Once the BIOS has initialized the hardware components it hands control to the
    bootloader stored in this partition.
  - The bootloader loads the kernel contained in its partition, into memory

  ### Root partition (`/`)

  - This houses everything to do with the operation of the operating system apart
    from the initial booting process. Once the kernel is in memory it accesses the
    resources in the root partition to get the OS up and running. These resources
    include system libraries, utilities, system-wide configs and application
    software.

  - The root partition is vital for the system's functionality. Without it, the
    system cannot boot or operate. It needs to be  
     large enough to accommodate the operating system, installed programs, and system
    libraries, but it doesn't need to store user data or  
     additional applications, which can be located on other partitions.

  - This is the domain of the [superuser](User_Space.md#root-user-superuser). The
    part of the filesystem that you need sudo priveleges to access and where you
    manage users

  ### Home partition

  - This is presented as `/home/`, i.e. that it is a descendent of `/`. But this
    is because the Linux file system is hierarchical. Typically `/home/` is
    usually its own partition.
  - Separating user data and system data in this way protects user data during
    upgrades or reinstallation. Reinstalling or upgrading the OS can be done
    without affecting these files.
  - Each user has their own directory off of `/home`, e.g `/home/thomas`.
  - While the root partition (`/`) is essential for the operation of the OS,
    placing `/home` on a separate partition allows for better management of user
    data, enhancing the system's flexibility and the user's control over their own
    files, without compromising the integrity or performance of the OS. This
    approach exemplifies the Linux philosophy of giving the user control while
    maintaining a clear distinction between system  
    resources and user data.

  ## Types of partition table

  In the Linux world there are two main types: MBR and GPT. The type of table used
  determines how the OS boots. So although partition tables are also responsible
  for the partitioning of non-bootable sectors of a disk, **they are distinguished
  by the boot system they implement**. If we look at the output from `parted` and
  `fdisk` above we see that the harddrive uses the GPT partition type.

  #### Primary, extended and logical partitions

  Most standard partition tables allow for primary, extended and logical
  partitions. The primary partition is the part of the harddisk that contains the
  operating system and is thus described as 'bootable' and may be called the 'boot
  partition'. During the bootstrapping process this is injected into memory as the
  [kernel](The_kernel.md).

  The extended partition is basically everything other than the primary partition.
  This is typically subdivided into other partitions that are called _logical_
  partitions. This is because they physically reside in the same sector of the
  disk (the extended partition) but are treated as virtual and independent disks.

  In our example above:

  - `/dev/nvme0n1p1` is the primary/boot partition
  - `/dev/nvme0n1p2` and `/dev/nvme0n1p3` comprise the extended partition and by
    themselves are each logical partitions.

  <dl>
    <dt>MBR</dt>
    <dd> 
      <ul>
        <li>Stands for Master Boot Record</li> 
        <li>Uses BIOS in the boot process</li> 
        <li>Can only works with disks up to 2TB in size</li> 
        <li>Only supports 4 primary partitions. This means the number of operating systems you install is limitied to this number.</li> 
        <li>This is the first 512 bytes of a storage device, preceding the first partition.</li>
      </ul> 
    </dd>
    <dt>GPT</dt>
    <dd>
    <ul>
        <li>Stands for GUID Partition Table </li>
        <li>Gradually replacing MBR</li>
        <li>Uses UEFI instead of BIOS</li>
        <li>As name indicates, every partition on disk has its own globally-unique identifier</li>
        <li>Vastly more partitions available than with MBR (dependent on operating system)</li>
        <li>Offers greater recovery options and anti-corruption safeguards</li> 
      </ul>
  </dd>
  </dl>

  ## Related notes

  ![Creating a Linux partition table](./Creating_a_Linux_partition_table.md)

raw_content:
  ---
  tags:
    - disks
    - Linux
    - procedural
  ---

  # Linux disk partitions

  A disk is divided up into partitions which are subsections of the overall disk.
  The kernel presents each partition as a [block device](Devices.md#Devices) as it
  would with an entire disk.

  The disk dedicates a small part of its contents to a **partition table**: this
  defines the different partitions that comprise the total disk space.

  ## Viewing current partitions

  Whenever you install a Linux distribution on a real or virtual machine, you must
  partition the drive. There are three main tools to choose from: `parted`,
  `g(raphical)parted`, `fdisk`.

  For a top-level overview of your disks and their main partitions you can run
  `lsblk` (_list block devices_):

  ```bash
  $ lsblk

  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ├─sda1        8:1    0   200M  0 part
  └─sda2        8:2    0 465.4G  0 part /run/media/thomas/ganesh
  nvme0n1     259:0    0 476.9G  0 disk
  ├─nvme0n1p1 259:1    0   488M  0 part
  ├─nvme0n1p2 259:2    0  27.9G  0 part /
  └─nvme0n1p3 259:3    0 448.5G  0 part /home
  ```

  We can use `parted -l` to view the partition table for the current machine:

  ```bash
  Model: SKHynix_HFS512GDE9X081N (nvme)
  Disk /dev/nvme0n1: 512GB
  Sector size (logical/physical): 512B/512B
  Partition Table: gpt
  Disk Flags:

  Number  Start   End     Size    File system  Name  Flags
   1      1049kB  513MB   512MB   fat32              boot, esp
   2      513MB   30.5GB  30.0GB  ext4
   3      30.5GB  512GB   482GB   ext4
  ```

  We can use `fdisk -l` to get slightly more info:

  ```bash
  disk /dev/nvme0n1: 476.94 GiB, 512110190592 bytes, 1000215216 sectors
  Disk model: SKHynix_HFS512GDE9X081N
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 08175E77-CB9F-C34A-9032-DF29A3F8F0FE

  Device            Start        End   Sectors   Size Type
  /dev/nvme0n1p1     2048    1001471    999424   488M EFI System
  /dev/nvme0n1p2  1001472   59594751  58593280  27.9G Linux filesystem
  /dev/nvme0n1p3 59594752 1000214527 940619776 448.5G Linux filesystem
  ```

  ## Standard Linux partitions

  The two tools disclose that the main harddrive is `/dev/nvme0n1` (equivalent to
  `sda` on older machines running Linux) and it has the standard three partitions:

  - Boot partition (`/dev/nvme0n1p1`)
  - Root dir (`/dev/nvme0n1p2`)
  - Home dir (`/dev/nvme0n1p3`)

  ### Boot partition

  - Takes up the smallest amount of space
  - Contains the Linux kernel and the bootloader (GRUB, usually) and any other
    files required for booting.
  - Once the BIOS has initialized the hardware components it hands control to the
    bootloader stored in this partition.
  - The bootloader loads the kernel contained in its partition, into memory

  ### Root partition (`/`)

  - This houses everything to do with the operation of the operating system apart
    from the initial booting process. Once the kernel is in memory it accesses the
    resources in the root partition to get the OS up and running. These resources
    include system libraries, utilities, system-wide configs and application
    software.

  - The root partition is vital for the system's functionality. Without it, the
    system cannot boot or operate. It needs to be  
     large enough to accommodate the operating system, installed programs, and system
    libraries, but it doesn't need to store user data or  
     additional applications, which can be located on other partitions.

  - This is the domain of the [superuser](User_Space.md#root-user-superuser). The
    part of the filesystem that you need sudo priveleges to access and where you
    manage users

  ### Home partition

  - This is presented as `/home/`, i.e. that it is a descendent of `/`. But this
    is because the Linux file system is hierarchical. Typically `/home/` is
    usually its own partition.
  - Separating user data and system data in this way protects user data during
    upgrades or reinstallation. Reinstalling or upgrading the OS can be done
    without affecting these files.
  - Each user has their own directory off of `/home`, e.g `/home/thomas`.
  - While the root partition (`/`) is essential for the operation of the OS,
    placing `/home` on a separate partition allows for better management of user
    data, enhancing the system's flexibility and the user's control over their own
    files, without compromising the integrity or performance of the OS. This
    approach exemplifies the Linux philosophy of giving the user control while
    maintaining a clear distinction between system  
    resources and user data.

  ## Types of partition table

  In the Linux world there are two main types: MBR and GPT. The type of table used
  determines how the OS boots. So although partition tables are also responsible
  for the partitioning of non-bootable sectors of a disk, **they are distinguished
  by the boot system they implement**. If we look at the output from `parted` and
  `fdisk` above we see that the harddrive uses the GPT partition type.

  #### Primary, extended and logical partitions

  Most standard partition tables allow for primary, extended and logical
  partitions. The primary partition is the part of the harddisk that contains the
  operating system and is thus described as 'bootable' and may be called the 'boot
  partition'. During the bootstrapping process this is injected into memory as the
  [kernel](The_kernel.md).

  The extended partition is basically everything other than the primary partition.
  This is typically subdivided into other partitions that are called _logical_
  partitions. This is because they physically reside in the same sector of the
  disk (the extended partition) but are treated as virtual and independent disks.

  In our example above:

  - `/dev/nvme0n1p1` is the primary/boot partition
  - `/dev/nvme0n1p2` and `/dev/nvme0n1p3` comprise the extended partition and by
    themselves are each logical partitions.

  <dl>
    <dt>MBR</dt>
    <dd> 
      <ul>
        <li>Stands for Master Boot Record</li> 
        <li>Uses BIOS in the boot process</li> 
        <li>Can only works with disks up to 2TB in size</li> 
        <li>Only supports 4 primary partitions. This means the number of operating systems you install is limitied to this number.</li> 
        <li>This is the first 512 bytes of a storage device, preceding the first partition.</li>
      </ul> 
    </dd>
    <dt>GPT</dt>
    <dd>
    <ul>
        <li>Stands for GUID Partition Table </li>
        <li>Gradually replacing MBR</li>
        <li>Uses UEFI instead of BIOS</li>
        <li>As name indicates, every partition on disk has its own globally-unique identifier</li>
        <li>Vastly more partitions available than with MBR (dependent on operating system)</li>
        <li>Offers greater recovery options and anti-corruption safeguards</li> 
      </ul>
  </dd>
  </dl>

  ## Related notes

  ![Creating a Linux partition table](./Creating_a_Linux_partition_table.md)


path: zk/Creating_a_Linux_partition_table.md
sortable_path: zkCreating_a_Linux_partition_table.md
title: Creating_a_Linux_partition_table
lead: ## Creating a partition table
checksum: 81594b70c67dcb48f219bad83218bbc3c34ae53548dae081c5b9fab5ef72b461
created: 2024-05-06 12:29:42.564542506+00:00
modified: 2024-06-16 16:59:33.587399238+00:00
body:
  ## Creating a partition table

  To demonstrate the process of partitioning a harddrive I am going to repartition
  an external SATA drive as if it were being primed for a fresh Linux install.

  Let's take a look at the disk in its current form:

  ```
  $ fdisk -l

    Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
    Disk model: My Passport 071Aumount /dev/sda2
    Disklabel type: gpt
    Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

    Device      Start       End   Sectors   Size Type
    /dev/sda1      40    409639    409600   200M EFI System
    /dev/sda2  409640 976455639 976046000 465.4G Apple HFS/HFS+
  ```

  (This disk was previously used as a backup disk for MacOS so in addition to the
  extended partition which has a proprietary file system type (Apple HFS) it has a
  primary partition which would load the recovery OS. In contrast to my main
  harddrive this uses the standard SCSI prototcol and thus the partitions are
  prepended with `sda`.)

  #### 1. Unmount existing partitions

  ```bash
  umount /dev/sda1
  umount /dev/sda2
  ```

  #### 2. Deleting the existing partitions

  ```bash
  # Load the disk into fdisk
  $ sudo fdisk /dev/sda
  Command (m for help): d
  Partition number (1,2, default 2): 1
  Partition 1 has been deleted.
  Command (m for help): d
  Selected partition 2
  Partition 2 has been deleted.

  # Verify deletion with p(rint) command
  Command (m for help): p
  Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
  Disk model: My Passport 071A
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

  # Write the changes to disk with w(rite)
  w

  # Check execution:
  $ lsblk

  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ```

  So now the disk has no partitions, just the physical disk space and no
  mountpoints. We are ready to re-partition.

  #### 3. Re-partition the disk

  We are going to create a GPT partition table

  ```bash
  $ sudo fdisk /dev/sda
  Command (m for help): g
  Created a new GPT disklabel (GUID: E316B1A9-6F73-FB41-8CBB-FA4E3C448F2B).

  Command (m for help): n
  Partition number (1-128, default 1):
  First sector (2048-976717790, default 2048):

  # Just press enter here

  # The last sector is where we put the actual size we want for the partition
  Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-976717790, default 976715775): +100G
  Created a new partition 1 of type 'Linux filesystem' and of size 100 GiB.

  # For the second and final partition, we follow the same steps but don't add a partition size, since it will default to what is left.

  Command (m for help): n
  Partition number (2-128, default 2):
  First sector (209717248-976717790, default 209717248):
  Last sector, +/-sectors or +/-size{K,M,G,T,P} (209717248-976717790, default 976715775):

  Created a new partition 2 of type 'Linux filesystem' and of size 365.7 GiB.

  # Check the partitions with p(rint)
  Command (m for help): p
  Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
  Disk model: My Passport 071A
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 92739978-F7D2-5042-9758-C1429B5C8E11

  Device         Start       End   Sectors   Size Type
  /dev/sda1       2048 209717247 209715200   100G Linux filesystem
  /dev/sda2  209717248 976715775 766998528 365.7G Linux filesystem

  # Then write with w
  Command (m for help): w
  The partition table has been altered.
  Calling ioctl() to re-read partition table.
  Syncing disks.
  ```

  We can now confirm our new partitions:

  ```bash
  $ lsblk
  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ├─sda1        8:1    0   100G  0 part
  └─sda2        8:2    0 365.7G  0 part
  ```

  #### Naming a partition

  By default each partition will have its GUID as its name, but you can add a
  human friendly name with:

  ```bash
  sudo e2label /dev/sda1 my_human_name
  ```

  > Whilst we have created our partitions we cannot yet mount them. This is
  > because we have not yet set up a filesystem on the partitions. This is the
  > next step.

  ## Related notes

  ![Linux disk partitions](./Linux_disk_partitions.md)

raw_content:
  ---
  id: h7f8
  title: Creating_a_Linux_partition_table
  tags:
    - disks
    - Linux
  created: Monday, May 06, 2024
  ---

  ## Creating a partition table

  To demonstrate the process of partitioning a harddrive I am going to repartition
  an external SATA drive as if it were being primed for a fresh Linux install.

  Let's take a look at the disk in its current form:

  ```
  $ fdisk -l

    Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
    Disk model: My Passport 071Aumount /dev/sda2
    Disklabel type: gpt
    Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

    Device      Start       End   Sectors   Size Type
    /dev/sda1      40    409639    409600   200M EFI System
    /dev/sda2  409640 976455639 976046000 465.4G Apple HFS/HFS+
  ```

  (This disk was previously used as a backup disk for MacOS so in addition to the
  extended partition which has a proprietary file system type (Apple HFS) it has a
  primary partition which would load the recovery OS. In contrast to my main
  harddrive this uses the standard SCSI prototcol and thus the partitions are
  prepended with `sda`.)

  #### 1. Unmount existing partitions

  ```bash
  umount /dev/sda1
  umount /dev/sda2
  ```

  #### 2. Deleting the existing partitions

  ```bash
  # Load the disk into fdisk
  $ sudo fdisk /dev/sda
  Command (m for help): d
  Partition number (1,2, default 2): 1
  Partition 1 has been deleted.
  Command (m for help): d
  Selected partition 2
  Partition 2 has been deleted.

  # Verify deletion with p(rint) command
  Command (m for help): p
  Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
  Disk model: My Passport 071A
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 9993F1BB-626C-485F-8542-3CC73BB40953

  # Write the changes to disk with w(rite)
  w

  # Check execution:
  $ lsblk

  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ```

  So now the disk has no partitions, just the physical disk space and no
  mountpoints. We are ready to re-partition.

  #### 3. Re-partition the disk

  We are going to create a GPT partition table

  ```bash
  $ sudo fdisk /dev/sda
  Command (m for help): g
  Created a new GPT disklabel (GUID: E316B1A9-6F73-FB41-8CBB-FA4E3C448F2B).

  Command (m for help): n
  Partition number (1-128, default 1):
  First sector (2048-976717790, default 2048):

  # Just press enter here

  # The last sector is where we put the actual size we want for the partition
  Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-976717790, default 976715775): +100G
  Created a new partition 1 of type 'Linux filesystem' and of size 100 GiB.

  # For the second and final partition, we follow the same steps but don't add a partition size, since it will default to what is left.

  Command (m for help): n
  Partition number (2-128, default 2):
  First sector (209717248-976717790, default 209717248):
  Last sector, +/-sectors or +/-size{K,M,G,T,P} (209717248-976717790, default 976715775):

  Created a new partition 2 of type 'Linux filesystem' and of size 365.7 GiB.

  # Check the partitions with p(rint)
  Command (m for help): p
  Disk /dev/sda: 465.74 GiB, 500079525888 bytes, 976717824 sectors
  Disk model: My Passport 071A
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: gpt
  Disk identifier: 92739978-F7D2-5042-9758-C1429B5C8E11

  Device         Start       End   Sectors   Size Type
  /dev/sda1       2048 209717247 209715200   100G Linux filesystem
  /dev/sda2  209717248 976715775 766998528 365.7G Linux filesystem

  # Then write with w
  Command (m for help): w
  The partition table has been altered.
  Calling ioctl() to re-read partition table.
  Syncing disks.
  ```

  We can now confirm our new partitions:

  ```bash
  $ lsblk
  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ├─sda1        8:1    0   100G  0 part
  └─sda2        8:2    0 365.7G  0 part
  ```

  #### Naming a partition

  By default each partition will have its GUID as its name, but you can add a
  human friendly name with:

  ```bash
  sudo e2label /dev/sda1 my_human_name
  ```

  > Whilst we have created our partitions we cannot yet mount them. This is
  > because we have not yet set up a filesystem on the partitions. This is the
  > next step.

  ## Related notes

  ![Linux disk partitions](./Linux_disk_partitions.md)

metadata:
  {"created":"Monday, May 06, 2024","id":"h7f8","tags":["disks","Linux"],"title":"Creating_a_Linux_partition_table"}


path: zk/DynamoDB.md
sortable_path: zkDynamoDB.md
title: DynamoDB
lead: # DynamoDB
checksum: dd37e5cdd877dd5fad9cec869426f36bc4cd86842da2a435ed693134d28c2496
created: 2024-06-09 16:24:31.762182012+00:00
modified: 2024-06-15 09:47:47.456782021+00:00
body:
  # DynamoDB

  ## Data structure

  ### Non-relational tables

  DynamoDB is "NoSQL" because it does not support #SQL queries and is
  non-relational meaning there cannot be JOIN operations via
  [foreign_keys](Foreign_keys_in_SQL.md)

  ![](../img/dynamodb.png)

  ### Primary key

  Although the data is stored as a table, one of the attributes is a primary key
  and the rest of the attributes are effectively the "value" associated with it.

  Because DynamoDB is schemaless, neither the attributes or their data types need
  to be defined beforehand and each item can have its own distinct attributes.

  Each item in the table is uniquely identifiable by its primary key.

  There are two types of primary key available:

  - partition key: a simple primary key composed of one attribute only. Because
    the primary key is hash-mapped items can be retrieved very rapidly using the
    primary key. This would be the `personId` alone.

  - composite key: this comprises a partition key and a _sort key_ both of which
    are attributes. In a table that has a partition key and a sort key, it's
    possible for multiple items to have the same partition key value. However,
    those items must have different sort key values. You could then query by
    either key or both. For instance using the `personId` along with `LastName`

  ### Secondary index

  As well as the index provided by the primary key, you can set one or more
  **secondary indices**. A secondary index lets you query the data in the table
  using an alternate key.

  A **global secondary index** is useful for querying data that needs to be
  accessed using non-primary key attributes. For example, if you have a Users
  table with `UserID` as the primary key but often need to fetch users by their
  `Email`, a GSI on `Email` would be appropriate.

  There are also **local secondary indices** but I don't understand the
  difference.

  ## Real example

  Below is a specification of the DynamoDB table I am using for my time-entries
  project:

  ```json
  {
    "TableName": "TimeEntries",
    "AttributeDefinitions": [
      {
        "AttributeName": "activity_start_end",
        "AttributeType": "S"
      },
      {
        "AttributeName": "start",
        "AttributeType": "S"
      },
      {
        "AttributeName": "activity_type",
        "AttributeType": "S"
      }
    ],
    "KeySchema": [
      {
        "AttributeName": "activity_start_end",
        "KeyType": "HASH"
      }
    ],
    "GlobalSecondaryIndexes": [
      {
        "IndexName": "StartIndex",
        "KeySchema": [
          {
            "AttributeName": "start",
            "KeyType": "HASH"
          },
          {
            "AttributeName": "activity_type",
            "KeyType": "RANGE"
          }
        ],
        "Projection": {
          "ProjectionType": "ALL"
        }
      }
    ]
  }
  ```

  This defines the attribute `activity_start_end` as the primary key. This string
  (`S`) value is a concatenation of three attributes, which is a way of ensuring
  each entry for the attribute will be unique.

  I also define two GSIs. -- check that these are correct for getting entries by
  range!

  ## Usage

  ## Related notes

raw_content:
  ---
  id: xowl
  title: DynamoDB
  tags:
    - AWS
    - databases
    - dynamodb
  created: Sunday, June 09, 2024
  ---

  # DynamoDB

  ## Data structure

  ### Non-relational tables

  DynamoDB is "NoSQL" because it does not support #SQL queries and is
  non-relational meaning there cannot be JOIN operations via
  [foreign_keys](Foreign_keys_in_SQL.md)

  ![](../img/dynamodb.png)

  ### Primary key

  Although the data is stored as a table, one of the attributes is a primary key
  and the rest of the attributes are effectively the "value" associated with it.

  Because DynamoDB is schemaless, neither the attributes or their data types need
  to be defined beforehand and each item can have its own distinct attributes.

  Each item in the table is uniquely identifiable by its primary key.

  There are two types of primary key available:

  - partition key: a simple primary key composed of one attribute only. Because
    the primary key is hash-mapped items can be retrieved very rapidly using the
    primary key. This would be the `personId` alone.

  - composite key: this comprises a partition key and a _sort key_ both of which
    are attributes. In a table that has a partition key and a sort key, it's
    possible for multiple items to have the same partition key value. However,
    those items must have different sort key values. You could then query by
    either key or both. For instance using the `personId` along with `LastName`

  ### Secondary index

  As well as the index provided by the primary key, you can set one or more
  **secondary indices**. A secondary index lets you query the data in the table
  using an alternate key.

  A **global secondary index** is useful for querying data that needs to be
  accessed using non-primary key attributes. For example, if you have a Users
  table with `UserID` as the primary key but often need to fetch users by their
  `Email`, a GSI on `Email` would be appropriate.

  There are also **local secondary indices** but I don't understand the
  difference.

  ## Real example

  Below is a specification of the DynamoDB table I am using for my time-entries
  project:

  ```json
  {
    "TableName": "TimeEntries",
    "AttributeDefinitions": [
      {
        "AttributeName": "activity_start_end",
        "AttributeType": "S"
      },
      {
        "AttributeName": "start",
        "AttributeType": "S"
      },
      {
        "AttributeName": "activity_type",
        "AttributeType": "S"
      }
    ],
    "KeySchema": [
      {
        "AttributeName": "activity_start_end",
        "KeyType": "HASH"
      }
    ],
    "GlobalSecondaryIndexes": [
      {
        "IndexName": "StartIndex",
        "KeySchema": [
          {
            "AttributeName": "start",
            "KeyType": "HASH"
          },
          {
            "AttributeName": "activity_type",
            "KeyType": "RANGE"
          }
        ],
        "Projection": {
          "ProjectionType": "ALL"
        }
      }
    ]
  }
  ```

  This defines the attribute `activity_start_end` as the primary key. This string
  (`S`) value is a concatenation of three attributes, which is a way of ensuring
  each entry for the attribute will be unique.

  I also define two GSIs. -- check that these are correct for getting entries by
  range!

  ## Usage

  ## Related notes

metadata:
  {"created":"Sunday, June 09, 2024","id":"xowl","tags":["AWS","databases","dynamodb"],"title":"DynamoDB"}


path: zk/Network_scanning.md
sortable_path: zkNetwork_scanning.md
title: Network scanning
lead: # Network scanning
checksum: eb7a61101a4e8fb6df7031b46992b7bc54dadb99e5895bfc7fcbd3cc6d9930ef
created: 2024-06-10 18:04:10.389369098+00:00
modified: 2024-06-12 17:30:30.934189688+00:00
body:
  # Network scanning

  ## List all connected devices on local WiFi network

  ```sh
  arp-scan --interface=wlan0 --localnet
  ```

  ## Scan subnet for all connected devices (in case hiding)

  ```sh
  nmap -sn 192.168.0.0/24
  ```

  ## Check DNS resolution

  ```sh
  dig google.com
  ```

  Key output:

  ```
  ;; Query time: 6 msec
  ;; SERVER: 192.168.0.4#53(192.168.0.4) (UDP)
  ;; WHEN: Wed Jun 12 18:27:27 BST 2024
  ;; MSG SIZE  rcvd: 55
  ```

raw_content:
  ---
  id: ippn
  title: Network scanning
  tags: [networks, procedural, Linux]
  created: Monday, June 10, 2024
  ---

  # Network scanning

  ## List all connected devices on local WiFi network

  ```sh
  arp-scan --interface=wlan0 --localnet
  ```

  ## Scan subnet for all connected devices (in case hiding)

  ```sh
  nmap -sn 192.168.0.0/24
  ```

  ## Check DNS resolution

  ```sh
  dig google.com
  ```

  Key output:

  ```
  ;; Query time: 6 msec
  ;; SERVER: 192.168.0.4#53(192.168.0.4) (UDP)
  ;; WHEN: Wed Jun 12 18:27:27 BST 2024
  ;; MSG SIZE  rcvd: 55
  ```

metadata:
  {"created":"Monday, June 10, 2024","id":"ippn","tags":["networks","procedural","Linux"],"title":"Network scanning"}


path: zk/Headless_network_setup.md
sortable_path: zkHeadless_network_setup.md
title: Headless network setup
lead: # Headless network setup
checksum: 1bce08c92b873f341ec1cf412f3e29399447fd7c29d55a5318585ca94af063b7
created: 2024-06-12 17:45:11.903958951+00:00
modified: 2024-06-16 17:12:09.851084087+00:00
body:
  # Headless network setup

  If you are using a headless system and you aren't using an ethernet connection,
  you face a chicken-egg issue of how to connect the device to WiFi via `ssh` when
  the device isn't yet on the network.

  You can get around this by saving a file called `wp_supplicant.conf` to the
  `/boot` directory of the device. This specifies the SSID name and password and
  will be used to auto-connect when the device boots.

  For example:

  ```
  country=GB
  ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
  update_config=1
  network={
       ssid="SKYVL7XP"
       scan_ssid=1
       psk="WIFI_PASSWORD"
       key_mgmt=WPA-PSK
  }
  ```

  ## Related notes

raw_content:
  ---
  id: hb10
  title: Headless network setup
  tags:
    - networks
    - Linux
    - raspberry-pi
  created: Wednesday, June 12, 2024
  ---

  # Headless network setup

  If you are using a headless system and you aren't using an ethernet connection,
  you face a chicken-egg issue of how to connect the device to WiFi via `ssh` when
  the device isn't yet on the network.

  You can get around this by saving a file called `wp_supplicant.conf` to the
  `/boot` directory of the device. This specifies the SSID name and password and
  will be used to auto-connect when the device boots.

  For example:

  ```
  country=GB
  ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
  update_config=1
  network={
       ssid="SKYVL7XP"
       scan_ssid=1
       psk="WIFI_PASSWORD"
       key_mgmt=WPA-PSK
  }
  ```

  ## Related notes

metadata:
  {"created":"Wednesday, June 12, 2024","id":"hb10","tags":["networks","Linux","raspberry-pi"],"title":"Headless network setup"}


path: zk/Set_DNS_settings.md
sortable_path: zkSet_DNS_settings.md
title: Set DNS settings
lead: # Set DNS settings
checksum: 2d9bd8829f39b253bf3aea38a6d968fe309c1ddc349dcf7eebab87f45d553c5c
created: 2024-06-12 17:45:11.913843931+00:00
modified: 2024-06-17 19:02:01.968281493+00:00
body:
  # Set DNS settings

  ## Change the default DNS server

  On Arch and most modern Linux distributions domain name resolution is handled
  via the `systemd-resolved` #systemd configuration.

  Within the system systemd files this will be handled in
  `/etc/systemd/network/wired.network` or `/etc/systemd/network/wlan.network`
  files etc.

  In the file below I have turned of DHCP routing and specified the address of my
  Pi-Hole device to handle domain name resolution:

  ```
  #wlan.network

  [Match]
  Name=wl*

  [Link]
  RequiredForOnline=routable

  [Network]
  DHCP=yes
  DNS=192.168.0.4
  MulticastDNS=yes

  [DHCPv4]
  UseDNS=no
  RouteMetric=600

  [IPv6AcceptRA]
  RouteMetric=600

  ```

  This stops it using the default DNS server of my router and runs the resolutions
  against Pi-Hole.

  This should automatically update the two `resolv.conf` files (which should be in
  syc), viz:

  ```
  # File: /run/NetworkManager/resolv.conf
  # Generated by NetworkManager
  nameserver 192.168.0.4
  nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

  ```

  ```
  # File: /etc/resolv.conf
  # Generated by NetworkManager
  nameserver 192.168.0.4
  nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

  ```

  ## Related notes

  ![Network scanning](./Network_scanning.md)
  ![Network debugging](Network_debugging.md)

raw_content:
  ---
  id: 2w0e
  title: Set DNS settings
  tags: [Linux, networks]
  created: Wednesday, June 12, 2024
  ---

  # Set DNS settings

  ## Change the default DNS server

  On Arch and most modern Linux distributions domain name resolution is handled
  via the `systemd-resolved` #systemd configuration.

  Within the system systemd files this will be handled in
  `/etc/systemd/network/wired.network` or `/etc/systemd/network/wlan.network`
  files etc.

  In the file below I have turned of DHCP routing and specified the address of my
  Pi-Hole device to handle domain name resolution:

  ```
  #wlan.network

  [Match]
  Name=wl*

  [Link]
  RequiredForOnline=routable

  [Network]
  DHCP=yes
  DNS=192.168.0.4
  MulticastDNS=yes

  [DHCPv4]
  UseDNS=no
  RouteMetric=600

  [IPv6AcceptRA]
  RouteMetric=600

  ```

  This stops it using the default DNS server of my router and runs the resolutions
  against Pi-Hole.

  This should automatically update the two `resolv.conf` files (which should be in
  syc), viz:

  ```
  # File: /run/NetworkManager/resolv.conf
  # Generated by NetworkManager
  nameserver 192.168.0.4
  nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

  ```

  ```
  # File: /etc/resolv.conf
  # Generated by NetworkManager
  nameserver 192.168.0.4
  nameserver fded:2060:8671:0:681:9bff:fe9b:37f0

  ```

  ## Related notes

  ![Network scanning](./Network_scanning.md)
  ![Network debugging](Network_debugging.md)

metadata:
  {"created":"Wednesday, June 12, 2024","id":"2w0e","tags":["Linux","networks"],"title":"Set DNS settings"}


path: zk/5__Integrating_the_Mongo_database.md
sortable_path: zk5__Integrating_the_Mongo_database.md
title: Creating a RESTful API: Integrating the database
checksum: 538034760405536a2f4949cde906dd4398f0f43c0e8e59a51357aae3c5fe19f0
created: 2024-06-16 17:06:08.163986495+00:00
modified: 2024-06-15 10:04:45.832445734+00:00
metadata: {"tags":["node-js","REST","APIs","mongo-db","databases"]}
lead:
  So far we have set up the application and an `/api/courses` route which handles
  requests for RESTful API operations on a local array of course objects. We now
  want to have the endpoints operate on a MongoDB `courses` collection rather than
  the array.

body:
  So far we have set up the application and an `/api/courses` route which handles
  requests for RESTful API operations on a local array of course objects. We now
  want to have the endpoints operate on a MongoDB `courses` collection rather than
  the array.

  ## Set-up

  We will follow the routine for establishing a MongoDB instance as detailed in
  [my notes](Connect_to_Mongo_database.md) on Mongo:

  - [Create MongoDB database](Create_Mongo_database.md)
  - [Connect to MongoDB database](Connect_to_Mongo_database.md)

  Our `index.js` now looks like the following:

  ```js
  // index.js

  // Connect to database
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));

  app.use(express.json());

  // Link to `courses` route which contains our REST request handlers for this part of the API
  app.use("/api/courses", courses);
  ```

  ## Integrating Mongo with our our `courses` module

  ### Create the schema

  Now we go the router module for `courses` and start to use Mongoose, defining
  our `Course` schema:

  ```diff
  // index.js

  // Connect to database
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));

  app.use(express.json());

  // Link to `courses` route which contains our REST request handlers for this part of the API
  app.use("/api/courses", courses);

  + const courseSchema = new mongoose.Schema({
  +  name: {type: String, required: true, minlength: 5, maxlength: 255},
  +  author: String,
  +  tags: [String],
  +  data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
  +  isPublished: Boolean,
  + });

  ```

  ### Create a model

  ```diff
  const courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });

  + const Course = new mongoose.model('Course', courseSchema);
  ```

  With this established we can remove our local array as we are ready to start
  getting our data from the database:

  ```diff
  const Course = mongoose.model('Course', courseSchema);

  - const courses = [
  -  {
  -    id: 1,
  -    name: "First course",
  -  },
  -  ...
  -];
  ```

  We could actually simplify the syntax here and combine our schema and model
  declaration into a single block:

  ```js
  const Course = mongoose.model(
    "Course",
    new mongoose.Schema({
      name: { type: String, required: true, minlength: 5, maxlength: 255 },
      author: String,
      tags: [String],
      data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
      isPublished: Boolean,
    })
  );
  ```

  > N.B In a real project we wouldn't keep our models in the same file as our
  > handlers. We would keep them in the dedicated `/models/` directory. We should
  > stick to the single responsibility principle and keep `/routes/` for API
  > handlers and `/model/` for schema declarations and models.

  ## Rewriting the REST handlers

  Now we need to rewrite our RESTful request handlers so that the data is sourced
  from and added to the database. We will mainly be using the Mongo syntax defined
  at [Querying a collection](Querying_a_Mongo_collection.md) and
  [Adding documents to a collection](Adding_documents_to_a_Mongo_collection.md).
  We will also keep API validation within the `/model/` file.

  ### GET

  Instead of simply returning the array, we use the Mongoose `find` method.

  ```diff
  - router.get("/", (req, res) => {
  -  res.send(courses);
   });

  + router.get("/", async (res, res) => {
  +  const courses = await Courses.find();
    res.send(courses)
  })
  ```

  ### POST

  Now we make our new course an instance of the `Courses` model:

  ```js
  // Original formulation

  router.post("/", (req, res) => {
  -  const course = {
  -    id: courses.length + 1,
  -    name: req.body.name,
  -  };
    courses.push(course);
    res.send(course);
  });
  ```

  ```diff
  router.post("/", async (req, res) => {
  +  let course = new Course({ // make new course instance of Course model
  -   id: courses.length + 1, // not needed as DB automatically adds an id
      name: req.body.name,
    });
  - courses.push(course); // not pushing to the array anymore
  + await course.save() // save to Mongo
    res.send(course);
  });

  ```

  ### PUT

  When updating a value in the database we are going to use the
  [query-first](Update_a_Mongo_document.md#query-first-document-update)
  approach to updating a Mongo document.

  ```jsconst courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });
  router.put("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));

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

    const { error } = validateCourse(req.body);
    if (error)
      return error.details.map((joiErr) => res.status(400).send(joiErr.message));
  const courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });
    course.name = req.body.name;
    res.send(course);
  });
  ```

  ```diff
  router.put("/:id", async (req, res) => {
  - const course = courses.find((c) => c.id === parseInt(req.params.id));
   const { error } = validateCourse(req.body);
   if (!course) return res.status(404).send("A course with the given ID was not found");
  + const updatedCourse = await Course.findByIdAndUpdate(req.params.id,
  +  { name: req.body.name },
  +  { new: true}
  + )

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

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

  ### DELETE

  ```js
  router.delete("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course)
      return res.status(404).send("A course with the given ID was not found");

    courses.indexOf(course);
    courses.splice(index, 1);
    res.send(course);
  });
  ```

  ```diff

  router.delete("/:id", async (req, res) => {
   const courseToDelete = await Course.findByIdAndRemove(req.params.id)

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

  - courses.indexOf(course);
  - courses.splice(index, 1);

  res.send(course);
  })
  ```

raw_content:
  ---
  tags:
    - node-js
    - REST
    - APIs
    - mongo-db
    - databases
  ---

  # Creating a RESTful API: Integrating the database

  So far we have set up the application and an `/api/courses` route which handles
  requests for RESTful API operations on a local array of course objects. We now
  want to have the endpoints operate on a MongoDB `courses` collection rather than
  the array.

  ## Set-up

  We will follow the routine for establishing a MongoDB instance as detailed in
  [my notes](Connect_to_Mongo_database.md) on Mongo:

  - [Create MongoDB database](Create_Mongo_database.md)
  - [Connect to MongoDB database](Connect_to_Mongo_database.md)

  Our `index.js` now looks like the following:

  ```js
  // index.js

  // Connect to database
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));

  app.use(express.json());

  // Link to `courses` route which contains our REST request handlers for this part of the API
  app.use("/api/courses", courses);
  ```

  ## Integrating Mongo with our our `courses` module

  ### Create the schema

  Now we go the router module for `courses` and start to use Mongoose, defining
  our `Course` schema:

  ```diff
  // index.js

  // Connect to database
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));

  app.use(express.json());

  // Link to `courses` route which contains our REST request handlers for this part of the API
  app.use("/api/courses", courses);

  + const courseSchema = new mongoose.Schema({
  +  name: {type: String, required: true, minlength: 5, maxlength: 255},
  +  author: String,
  +  tags: [String],
  +  data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
  +  isPublished: Boolean,
  + });

  ```

  ### Create a model

  ```diff
  const courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });

  + const Course = new mongoose.model('Course', courseSchema);
  ```

  With this established we can remove our local array as we are ready to start
  getting our data from the database:

  ```diff
  const Course = mongoose.model('Course', courseSchema);

  - const courses = [
  -  {
  -    id: 1,
  -    name: "First course",
  -  },
  -  ...
  -];
  ```

  We could actually simplify the syntax here and combine our schema and model
  declaration into a single block:

  ```js
  const Course = mongoose.model(
    "Course",
    new mongoose.Schema({
      name: { type: String, required: true, minlength: 5, maxlength: 255 },
      author: String,
      tags: [String],
      data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
      isPublished: Boolean,
    })
  );
  ```

  > N.B In a real project we wouldn't keep our models in the same file as our
  > handlers. We would keep them in the dedicated `/models/` directory. We should
  > stick to the single responsibility principle and keep `/routes/` for API
  > handlers and `/model/` for schema declarations and models.

  ## Rewriting the REST handlers

  Now we need to rewrite our RESTful request handlers so that the data is sourced
  from and added to the database. We will mainly be using the Mongo syntax defined
  at [Querying a collection](Querying_a_Mongo_collection.md) and
  [Adding documents to a collection](Adding_documents_to_a_Mongo_collection.md).
  We will also keep API validation within the `/model/` file.

  ### GET

  Instead of simply returning the array, we use the Mongoose `find` method.

  ```diff
  - router.get("/", (req, res) => {
  -  res.send(courses);
   });

  + router.get("/", async (res, res) => {
  +  const courses = await Courses.find();
    res.send(courses)
  })
  ```

  ### POST

  Now we make our new course an instance of the `Courses` model:

  ```js
  // Original formulation

  router.post("/", (req, res) => {
  -  const course = {
  -    id: courses.length + 1,
  -    name: req.body.name,
  -  };
    courses.push(course);
    res.send(course);
  });
  ```

  ```diff
  router.post("/", async (req, res) => {
  +  let course = new Course({ // make new course instance of Course model
  -   id: courses.length + 1, // not needed as DB automatically adds an id
      name: req.body.name,
    });
  - courses.push(course); // not pushing to the array anymore
  + await course.save() // save to Mongo
    res.send(course);
  });

  ```

  ### PUT

  When updating a value in the database we are going to use the
  [query-first](Update_a_Mongo_document.md#query-first-document-update)
  approach to updating a Mongo document.

  ```jsconst courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });
  router.put("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));

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

    const { error } = validateCourse(req.body);
    if (error)
      return error.details.map((joiErr) => res.status(400).send(joiErr.message));
  const courseSchema = new mongoose.Schema({
    name: {type: String, required: true, minlength: 5, maxlength: 255},
    author: String,
    tags: [String],
    data: {type: Date, default: Date.now}, // if unspecified, entry will default to current date
    isPublished: Boolean,
   });
    course.name = req.body.name;
    res.send(course);
  });
  ```

  ```diff
  router.put("/:id", async (req, res) => {
  - const course = courses.find((c) => c.id === parseInt(req.params.id));
   const { error } = validateCourse(req.body);
   if (!course) return res.status(404).send("A course with the given ID was not found");
  + const updatedCourse = await Course.findByIdAndUpdate(req.params.id,
  +  { name: req.body.name },
  +  { new: true}
  + )

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

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

  ### DELETE

  ```js
  router.delete("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course)
      return res.status(404).send("A course with the given ID was not found");

    courses.indexOf(course);
    courses.splice(index, 1);
    res.send(course);
  });
  ```

  ```diff

  router.delete("/:id", async (req, res) => {
   const courseToDelete = await Course.findByIdAndRemove(req.params.id)

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

  - courses.indexOf(course);
  - courses.splice(index, 1);

  res.send(course);
  })
  ```


path: zk/Adding_documents_to_a_Mongo_collection.md
sortable_path: zkAdding_documents_to_a_Mongo_collection.md
title: Adding documents to a collection
checksum: c8d62e948fd02c6e17f06f9f86160fc06534336683a11c46439528ba0a6a6a41
created: 2024-06-16 17:06:08.252028118+00:00
modified: 2024-06-15 09:57:02.990710464+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
lead:
  We have our database (`playground`) and collection (`courses`) established. We
  now need to add documents to our collection. We will do this via a function
  since this will be an asynchronous process:

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

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

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

  addCourseDocToDb(nodeCourse);
  ```

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

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

  This will also be reflected in Compass:

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

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Adding documents to a collection

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

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

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

  addCourseDocToDb(nodeCourse);
  ```

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

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

  This will also be reflected in Compass:

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


path: zk/Application_state_management_with_React_hooks.md
sortable_path: zkApplication_state_management_with_React_hooks.md
title: Application state management
checksum: da892726957c790ec1bce967b56554aea92feeb3b52aed639a7ae0dae3d3a10e
created: 2024-06-16 17:06:08.257788818+00:00
modified: 2024-06-15 10:16:42.954140592+00:00
metadata: {"tags":["javascript","react"]}
lead:
  Although [React_useReducer](React_useReducer.md) and [React_useContext](React_useContext.md) have
  many sound use cases by themselves, when they are combined they offer a way to
  acheive a system of global state management, without utilising third-party
  libraries like Redux.

body:
  Although [React_useReducer](React_useReducer.md) and [React_useContext](React_useContext.md) have
  many sound use cases by themselves, when they are combined they offer a way to
  acheive a system of global state management, without utilising third-party
  libraries like Redux.

  ## Requirements

  The Context API combined with a reducer addresses the following needs:

  - be able to consume global state from anywhere in the component hierarchy
    without prop-drilling
  - update global state from within child components from anywhere in the
    component hierarchy
  - access, maintain and update complex structured data (arrays/objects) not just
    single values, as global state

  ## Implementation

  In essence the approach is as follows:

  - Create a context provider that houses the global state object
  - Attach this state to a reducer function that operates on the state object
    through dispatch methods

  First off, our initial state and overall state object:

  ```js
  const initialState = {
    count: 0,
  };
  ```

  Next, we create our context. This is what we will invoke when we want to consume
  our state.

  ```js
  export const CounterContext = React.createContext({});
  ```

  Now we need a reducer that will handle the state updates. We will just use the
  same setup as we used in the example of
  [React_useReducer](React_useReducer.md#refining-the-syntax):

  ```js
  function reducer(state, action) {
    switch (action.type) {
      case "increase":
        return { ...state, counter: state.counter + 1 };
        break;
      case "decrease":
        return { ...state, counter: state.counter - 1 };
        break;
      case "increase_by_payload":
        return { ...state, counter: state.counter + action.payload };
      default:
        throw new Error();
    }
    return newState;
  }
  ```

  Finally, we need to make a provider as a top-level component that receives the
  reducer's `state` and `dispatch` methods as props:

  ```js
  export const CounterProvider = ({children}) => {
      // We pass our reducer function and initial state to useReducer as params
      const [state, dispatch] = React.useReducer(reducer, initialState)

      // We create our provider and pass the reducer state and update method as props. This is the provider to the CounterContext consumer
      <CounterContext.Provider value={{state, dispatch}}>
          {children}
      </CounterContext.Provider>
  }
  ```

  Now whenever we want to consume or update our global state, we can invoke the
  context within a lower-level component, for example:

  ```js
  const {state, dispatch} = useContext(CounterContext);

  dispatch({
      type 'increase_by_payload',
      payload: 4
  })

  console.log(state.counter) // 4

  ```

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

  # Application state management

  Although [React_useReducer](React_useReducer.md) and [React_useContext](React_useContext.md) have
  many sound use cases by themselves, when they are combined they offer a way to
  acheive a system of global state management, without utilising third-party
  libraries like Redux.

  ## Requirements

  The Context API combined with a reducer addresses the following needs:

  - be able to consume global state from anywhere in the component hierarchy
    without prop-drilling
  - update global state from within child components from anywhere in the
    component hierarchy
  - access, maintain and update complex structured data (arrays/objects) not just
    single values, as global state

  ## Implementation

  In essence the approach is as follows:

  - Create a context provider that houses the global state object
  - Attach this state to a reducer function that operates on the state object
    through dispatch methods

  First off, our initial state and overall state object:

  ```js
  const initialState = {
    count: 0,
  };
  ```

  Next, we create our context. This is what we will invoke when we want to consume
  our state.

  ```js
  export const CounterContext = React.createContext({});
  ```

  Now we need a reducer that will handle the state updates. We will just use the
  same setup as we used in the example of
  [React_useReducer](React_useReducer.md#refining-the-syntax):

  ```js
  function reducer(state, action) {
    switch (action.type) {
      case "increase":
        return { ...state, counter: state.counter + 1 };
        break;
      case "decrease":
        return { ...state, counter: state.counter - 1 };
        break;
      case "increase_by_payload":
        return { ...state, counter: state.counter + action.payload };
      default:
        throw new Error();
    }
    return newState;
  }
  ```

  Finally, we need to make a provider as a top-level component that receives the
  reducer's `state` and `dispatch` methods as props:

  ```js
  export const CounterProvider = ({children}) => {
      // We pass our reducer function and initial state to useReducer as params
      const [state, dispatch] = React.useReducer(reducer, initialState)

      // We create our provider and pass the reducer state and update method as props. This is the provider to the CounterContext consumer
      <CounterContext.Provider value={{state, dispatch}}>
          {children}
      </CounterContext.Provider>
  }
  ```

  Now whenever we want to consume or update our global state, we can invoke the
  context within a lower-level component, for example:

  ```js
  const {state, dispatch} = useContext(CounterContext);

  dispatch({
      type 'increase_by_payload',
      payload: 4
  })

  console.log(state.counter) // 4

  ```


path: zk/Basic_prop_passing_in_React.md
sortable_path: zkBasic_prop_passing_in_React.md
title: Test: Basic prop passing
lead:
  ```js
  import { render, screen } from "@testing-library/react";

checksum: 993345f8e5dee18e7890d64e30484fee3dc60f56195cf3f5155e23ba6479b4ee
created: 2024-06-16 17:06:08.298039624+00:00
modified: 2024-03-27 10:45:52.500191986+00:00
metadata: {"tags":["javascript","react","testing"]}
body:
  ```js
  import { render, screen } from "@testing-library/react";

  describe("<CertificateHtml />", () => {
    it("should render the values passed as props", () => {
      // Arrange:
      const stub = {
        titleOfActivityOrProgramme: "Filming",
        nameOfDepartment: "The film department",
      };

      // Act:
      render(<CertificateHtml {...stub} />);

      // Assert:
      expect(screen.getByText("Filming")).toBeInTheDocument();
      expect(screen.getByText("The film department")).toBeInTheDocument();
    });
  });
  ```

  Or, loop:

  ```js
  for (const entry of Object.values(stub)) {
    expect(screen.getByText(entry)).toBeInTheDocument();
  }
  ```

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

  # Test: Basic prop passing

  ```js
  import { render, screen } from "@testing-library/react";

  describe("<CertificateHtml />", () => {
    it("should render the values passed as props", () => {
      // Arrange:
      const stub = {
        titleOfActivityOrProgramme: "Filming",
        nameOfDepartment: "The film department",
      };

      // Act:
      render(<CertificateHtml {...stub} />);

      // Assert:
      expect(screen.getByText("Filming")).toBeInTheDocument();
      expect(screen.getByText("The film department")).toBeInTheDocument();
    });
  });
  ```

  Or, loop:

  ```js
  for (const entry of Object.values(stub)) {
    expect(screen.getByText(entry)).toBeInTheDocument();
  }
  ```


path: zk/Built_in_React_hooks.md
sortable_path: zkBuilt_in_React_hooks.md
title: Typing built-in hooks
lead: ## `useState`
checksum: 16efeb56bb48c15813a9a8693b69ac5532ab281fbd7acbd3166d82ee5e1b721f
created: 2024-06-16 17:06:08.407038333+00:00
modified: 2024-06-15 10:07:23.685272098+00:00
metadata: {"tags":["typescript","react"]}
body:
  ## `useState`

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

  ### With a ustom type

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

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

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

  // Alternative declaration

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

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

  ## `useReducer`

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

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

  const initialState = { count: 0 };

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

  Then the syntax is as normal, i.e:

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

  ## `useEffect`

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

  ## `useContext`

  We can use generics but mostly this is untyped:

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

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

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

  ## `useCallback` / `useMemo`

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

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

  # Typing built-in hooks

  ## `useState`

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

  ### With a ustom type

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

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

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

  // Alternative declaration

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

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

  ## `useReducer`

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

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

  const initialState = { count: 0 };

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

  Then the syntax is as normal, i.e:

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

  ## `useEffect`

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

  ## `useContext`

  We can use generics but mostly this is untyped:

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

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

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

  ## `useCallback` / `useMemo`

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


path: zk/Child_to_parent_data_flow_in_React.md
sortable_path: zkChild_to_parent_data_flow_in_React.md
title: Child to parent data flow
checksum: 63856c6f093fdced5941549b4f278df726d284bb3eea79e182d5c3c8b0af24dd
created: 2024-06-16 17:06:08.483513137+00:00
modified: 2024-06-15 10:08:01.602615809+00:00
metadata: {"tags":["javascript","react"]}
lead:
  Despite React having a uni-directional, downwards data-flow, it is sometimes
  necessary to pass events and data from a child back up to the parent. This need
  can arise when you want to modularize functionality within a child component
  rather than have everything happening in the parent, and you don't want to use a
  common shared higher context.

body:
  Despite React having a uni-directional, downwards data-flow, it is sometimes
  necessary to pass events and data from a child back up to the parent. This need
  can arise when you want to modularize functionality within a child component
  rather than have everything happening in the parent, and you don't want to use a
  common shared higher context.

  For the example we will use the standard click incrementer.

  We have a counter on the parent that is updated in response to a click event in
  the child component.

  Our parent component is `App` and the child component is `Child`

  ```jsx
  export default function App() {
    const [count, setCount] = useState(0);
    return (
      <>
        <p>{count}</p>
        <Child count={count} setCount={setCount} />
      </>
    );
  }

  const Child = ({ count, setCount }) => {
    return <button onClick={() => setCount(count + 1)}>Increment</button>;
  };
  ```

  So the overall state and updater function exists on the parent. The child is
  able to access this state by virtue of receiving `{count, setCount}` as props.
  It can therefore manipulate this state and have it be reflected in the parent.

  It is not necessary to pass the state variable every time. You could just pass
  the updater. We have passed the `count` variable here because the child needs
  access to the current value, in order to be able to increment it.

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

  # Child to parent data flow

  Despite React having a uni-directional, downwards data-flow, it is sometimes
  necessary to pass events and data from a child back up to the parent. This need
  can arise when you want to modularize functionality within a child component
  rather than have everything happening in the parent, and you don't want to use a
  common shared higher context.

  For the example we will use the standard click incrementer.

  We have a counter on the parent that is updated in response to a click event in
  the child component.

  Our parent component is `App` and the child component is `Child`

  ```jsx
  export default function App() {
    const [count, setCount] = useState(0);
    return (
      <>
        <p>{count}</p>
        <Child count={count} setCount={setCount} />
      </>
    );
  }

  const Child = ({ count, setCount }) => {
    return <button onClick={() => setCount(count + 1)}>Increment</button>;
  };
  ```

  So the overall state and updater function exists on the parent. The child is
  able to access this state by virtue of receiving `{count, setCount}` as props.
  It can therefore manipulate this state and have it be reflected in the parent.

  It is not necessary to pass the state variable every time. You could just pass
  the updater. We have passed the `count` variable here because the child needs
  access to the current value, in order to be able to increment it.


path: zk/Comparing_React_classes_to_hooks.md
sortable_path: zkComparing_React_classes_to_hooks.md
title: Comparing class components to hook-based components
lead:
  We will look at the same component written with hooks and classes. Both use this
  child component:

checksum: 5ed406f78142c4075d1118c27ed9b0cf5d84269988210b765ffd1386709946c1
created: 2024-06-16 17:06:08.559532679+00:00
modified: 2024-06-15 10:07:39.545555372+00:00
metadata: {"tags":["javascript","react"]}
body:
  We will look at the same component written with hooks and classes. Both use this
  child component:

  ```jsx
  const CounterBox = (props) => {
    return <div className="output">{props.counterValue}</div>;
  };
  ```

  ## Class component

  ```jsx
  import CounterBox from "./CounterBox";

  class CounterClass extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        counterValue: 0,
      };
    }

    addOne() {
      this.setState({
        counterValue: this.state.counterValue + 1,
      });
    }

    render() {
      return (
        <React.Fragment>
          <button onClick={() => this.addOne()}>Add One</button>
          <CounterBox counterValue={this.state.counterValue} />
        </React.Fragment>
      );
    }
  }
  ```

  ## Hook version

  ```jsx
  import React, { useState } from "react";
  import CounterBox from "./CounterBox";

  function CounterHook() {
    const [counter, setCounter] = useState(0);
    const handleClick = () => setCounter(counter + 1);
    return (
      <React.Fragment>
        <button onClick={handleClick}>Add One</button>
        <CounterBox counterValue={counter}></CounterBox>
      </React.Fragment>
    );
  }
  ```

  ## Main differences

  - Obviously with hooks we use a function, not a class. We can therefore think of
    them as **simple components** that are able to handle state as well as props.
  - We have written the hook as a declared function but we could just as easily
    write it as a function expression or arrow function.
  - With the class, the state versioning is managed via the following properties
    on the `React.Component` class: `this.state` (start state) and `this.setState`
    (the change).
  - In both cases the function that actually creates the change is handled via an
    arrow function. With the hook we use the customary name `handleClick` .

  - The same process is managed in the hook via the `useState()` method. We
    effectively set 'before' and 'after' destructured variables on this method:

    ```jsx
    const [counter, setCounter] = useState(0);

    // Schematically:
    const [val, setVal] = useState(initialVal);
    ```

  ## Binding with class component state

  In the class component example we use an inline arrow function to execute
  `addOne()` however the official way to do it is to bind the event via the
  constructor method to avoid the problems created by `this` scope in classes.
  Using arrows is mostly fine and is less verbose, but it is important to
  understand the 'official' approach.

  The way to write the state change in this way is:

  ```jsx
  class CounterClass extends React.Component{
    constructor(props){
      super(props);
  		this.state = { counterValue: 0};
      this.handleClick = this.handleClick.bind(this); // bind the click to the class scope
    }

    handleClick(event){
      this.setState({
              counterValue: this.state.counterValue + 1;
      });
    }

    render(){
      return (
        <button type="button"
        onClick={this.handleClick}> // reference the class scope with `this`
        Click Me
        </button>
  			<CounterBox counterValue={this.state.counterValue}></CounterBox>
      );
    }
  }
  ```

  ## How hooks improve on class components

  - State, when managed via hooks can be easily decoupled from a specific
    component and reused elsewhere. This also means it can be tested separately
    from any specific component where it is applied. This is much harder to do
    with classes which are closely entangled with the non-state aspects of a
    component through `this` and binding:

    > With Hooks, you can extract stateful logic from a component so it can be
    > tested independently and reused. Hooks allow you to reuse stateful logic
    > without changing your component hierarchy. This makes it easy to share Hooks
    > among many components or with the community.

  - Hooks simplify lifestyle methods and the use of `componentDidMount` etc
    through the `useEffect` hook
  - Classes and `this` are confusing generally. Functions are easier to grasp and
    read.

  ## Relation to function components

  You can think of hooks as function components (previously known as stateless
  components) plus state. Previously function components were 'dumb' components.
  That is, they didn't allow for state management and generally used for layout.
  They could receive data as props but not state. This changes with hooks: you can
  add state to functions and no longer need to use classes exclusively for state.
  In fact you no longer need to use classes at all, unless you want to.

  > The stateful portion of a function component must be placed before the
  > `return()` statement in the function.

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

  # Comparing class components to hook-based components

  We will look at the same component written with hooks and classes. Both use this
  child component:

  ```jsx
  const CounterBox = (props) => {
    return <div className="output">{props.counterValue}</div>;
  };
  ```

  ## Class component

  ```jsx
  import CounterBox from "./CounterBox";

  class CounterClass extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        counterValue: 0,
      };
    }

    addOne() {
      this.setState({
        counterValue: this.state.counterValue + 1,
      });
    }

    render() {
      return (
        <React.Fragment>
          <button onClick={() => this.addOne()}>Add One</button>
          <CounterBox counterValue={this.state.counterValue} />
        </React.Fragment>
      );
    }
  }
  ```

  ## Hook version

  ```jsx
  import React, { useState } from "react";
  import CounterBox from "./CounterBox";

  function CounterHook() {
    const [counter, setCounter] = useState(0);
    const handleClick = () => setCounter(counter + 1);
    return (
      <React.Fragment>
        <button onClick={handleClick}>Add One</button>
        <CounterBox counterValue={counter}></CounterBox>
      </React.Fragment>
    );
  }
  ```

  ## Main differences

  - Obviously with hooks we use a function, not a class. We can therefore think of
    them as **simple components** that are able to handle state as well as props.
  - We have written the hook as a declared function but we could just as easily
    write it as a function expression or arrow function.
  - With the class, the state versioning is managed via the following properties
    on the `React.Component` class: `this.state` (start state) and `this.setState`
    (the change).
  - In both cases the function that actually creates the change is handled via an
    arrow function. With the hook we use the customary name `handleClick` .

  - The same process is managed in the hook via the `useState()` method. We
    effectively set 'before' and 'after' destructured variables on this method:

    ```jsx
    const [counter, setCounter] = useState(0);

    // Schematically:
    const [val, setVal] = useState(initialVal);
    ```

  ## Binding with class component state

  In the class component example we use an inline arrow function to execute
  `addOne()` however the official way to do it is to bind the event via the
  constructor method to avoid the problems created by `this` scope in classes.
  Using arrows is mostly fine and is less verbose, but it is important to
  understand the 'official' approach.

  The way to write the state change in this way is:

  ```jsx
  class CounterClass extends React.Component{
    constructor(props){
      super(props);
  		this.state = { counterValue: 0};
      this.handleClick = this.handleClick.bind(this); // bind the click to the class scope
    }

    handleClick(event){
      this.setState({
              counterValue: this.state.counterValue + 1;
      });
    }

    render(){
      return (
        <button type="button"
        onClick={this.handleClick}> // reference the class scope with `this`
        Click Me
        </button>
  			<CounterBox counterValue={this.state.counterValue}></CounterBox>
      );
    }
  }
  ```

  ## How hooks improve on class components

  - State, when managed via hooks can be easily decoupled from a specific
    component and reused elsewhere. This also means it can be tested separately
    from any specific component where it is applied. This is much harder to do
    with classes which are closely entangled with the non-state aspects of a
    component through `this` and binding:

    > With Hooks, you can extract stateful logic from a component so it can be
    > tested independently and reused. Hooks allow you to reuse stateful logic
    > without changing your component hierarchy. This makes it easy to share Hooks
    > among many components or with the community.

  - Hooks simplify lifestyle methods and the use of `componentDidMount` etc
    through the `useEffect` hook
  - Classes and `this` are confusing generally. Functions are easier to grasp and
    read.

  ## Relation to function components

  You can think of hooks as function components (previously known as stateless
  components) plus state. Previously function components were 'dumb' components.
  That is, they didn't allow for state management and generally used for layout.
  They could receive data as props but not state. This changes with hooks: you can
  add state to functions and no longer need to use classes exclusively for state.
  In fact you no longer need to use classes at all, unless you want to.

  > The stateful portion of a function component must be placed before the
  > `return()` statement in the function.


path: zk/Complete_Mongo_example.md
sortable_path: zkComplete_Mongo_example.md
title: MongoDB connection, set-up and data query: complete example
lead:
  ```js
  const mongoose = require("mongoose");

checksum: 5a56f5101e268df3d5310e77625532af679c2435d466d4e303ab8fa316dcff9a
created: 2024-06-16 17:06:08.563957305+00:00
modified: 2024-06-15 09:57:16.934300579+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
body:
  ```js
  const mongoose = require("mongoose");

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

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

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

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

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # MongoDB connection, set-up and data query: complete example

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

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

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

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

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


path: zk/Components_props_hooks_in_React.md
sortable_path: zkComponents_props_hooks_in_React.md
title: Components and props with hooks
lead: As of React 16.8 a class component can be expressed using a function-based hook.
checksum: 15c018061a8e397cfea50f3d2534a8030f03d46576d2586db7e574ba8cff0847
created: 2024-06-16 17:06:08.570896311+00:00
modified: 2024-06-15 10:07:41.832262871+00:00
metadata: {"tags":["javascript","react"]}
body:
  As of React 16.8 a class component can be expressed using a function-based hook.

  A class component:

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

  The same component expressed as a hook:

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

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

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

  ## How hooks are rendered

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

  ## Function components must be pure functions

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

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

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

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

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

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

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

  # Components and props with hooks

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

  A class component:

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

  The same component expressed as a hook:

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

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

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

  ## How hooks are rendered

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

  ## Function components must be pure functions

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

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

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

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

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

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


path: zk/Conditionals_in_Bash.md
sortable_path: zkConditionals_in_Bash.md
title: Conditionals in Bash
lead: ## If statements
checksum: fdcef36604a1998318aad2344da29e3528c8ba744128a50ebf65c5b70bdba92e
created: 2024-06-16 17:06:08.588965949+00:00
modified: 2024-03-27 10:45:52.500191986+00:00
metadata: {"tags":["shell"]}
body:
  ## If statements

  - Conditional blocks start with `if` and end with the inversion `fi` (this is a
    common syntactic pattern in bash)
  - The conditional expression must be placed in square brackets with spaces
    either side. The spaces matter: if you omit them, the code will not run
  - We designate the code to run when the conditional is met with `then`
  - We can incorporate else if logic with `elif`

  ## Basic example

  ```bash
  if [ -e $var ]; then
    # Do something
  else
    # Do something else
  fi
  ```

  ## If, else

  ```bash
  if [ "$myMove" -eq "$opponentMove" ]; then
      (( totalScore+=myMove+3 ))
    elif [ $absDiff -eq 2 ] && [ "$myMove" -gt "$opponentMove" ]; then
      (( totalScore+=myMove))
    elif [ $absDiff -eq 2 ] && [ "$opponentMove" -gt "$myMove" ]; then
      (( totalScore+=myMove+6))
    elif [ $absDiff -eq 1 ] && [ "$opponentMove" -gt "$myMove" ]; then
      (( totalScore+=myMove))
    elif [ $absDiff -eq 1 ] && [ "$myMove" -gt "$opponentMove" ]; then
      (( totalScore+=myMove+6))
    fi
  ```

  ## Nested conditionals

  ```bash
  if [[ "$line" =~ ^$ ]]; then
    if [[ "$runningTotal" -gt "$highest" ]]; then
      (( highest=runningTotal ))
    fi
    # Reset running sum
    (( runningTotal=0 ))
  fi
  ```

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

  # Conditionals in Bash

  ## If statements

  - Conditional blocks start with `if` and end with the inversion `fi` (this is a
    common syntactic pattern in bash)
  - The conditional expression must be placed in square brackets with spaces
    either side. The spaces matter: if you omit them, the code will not run
  - We designate the code to run when the conditional is met with `then`
  - We can incorporate else if logic with `elif`

  ## Basic example

  ```bash
  if [ -e $var ]; then
    # Do something
  else
    # Do something else
  fi
  ```

  ## If, else

  ```bash
  if [ "$myMove" -eq "$opponentMove" ]; then
      (( totalScore+=myMove+3 ))
    elif [ $absDiff -eq 2 ] && [ "$myMove" -gt "$opponentMove" ]; then
      (( totalScore+=myMove))
    elif [ $absDiff -eq 2 ] && [ "$opponentMove" -gt "$myMove" ]; then
      (( totalScore+=myMove+6))
    elif [ $absDiff -eq 1 ] && [ "$opponentMove" -gt "$myMove" ]; then
      (( totalScore+=myMove))
    elif [ $absDiff -eq 1 ] && [ "$myMove" -gt "$opponentMove" ]; then
      (( totalScore+=myMove+6))
    fi
  ```

  ## Nested conditionals

  ```bash
  if [[ "$line" =~ ^$ ]]; then
    if [[ "$runningTotal" -gt "$highest" ]]; then
      (( highest=runningTotal ))
    fi
    # Reset running sum
    (( runningTotal=0 ))
  fi
  ```


path: zk/Connect_to_Mongo_database.md
sortable_path: zkConnect_to_Mongo_database.md
title: Connect to a database with Mongoose
checksum: 7aaf3990da7ec46f0171cfe1671c406ad4f29d136007bff56c9e4ad840e092fa
created: 2024-06-16 17:06:08.594665135+00:00
modified: 2024-06-15 09:57:45.698162691+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
lead:
  Now that we have installed and configured MongoDB, we need to connect to it via
  Node.js. Mongoose is a simple API for interacting with a Mongo database via
  Node.

body:
  Now that we have installed and configured MongoDB, we need to connect to it via
  Node.js. Mongoose is a simple API for interacting with a Mongo database via
  Node.

  With Mongoose installed we can connect to a database. We don't have any Mongo
  databases yet beyond the defaults but the following Mongoose connection logic
  will create and connect to a new database called `playground`:

  Providing the Mongo server is running (execture `mongod`), we will see the
  confirmation message in the console.

  ```js
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));
  ```

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Connect to a database with Mongoose

  Now that we have installed and configured MongoDB, we need to connect to it via
  Node.js. Mongoose is a simple API for interacting with a Mongo database via
  Node.

  With Mongoose installed we can connect to a database. We don't have any Mongo
  databases yet beyond the defaults but the following Mongoose connection logic
  will create and connect to a new database called `playground`:

  Providing the Mongo server is running (execture `mongod`), we will see the
  confirmation message in the console.

  ```js
  mongoose
    .connect("mongodb://127.0.0.1/playground")
    .then(() => console.log("Connected to MongoDB"))
    .catch((err) => console.error(err));
  ```


path: zk/Controlled_components_in_React.md
sortable_path: zkControlled_components_in_React.md
title: Controlled components
lead: Controlled components relate to how you use forms in React.
checksum: af81e879e3f02c89c3466db77f21fa436c84f9a15d6ac37d6c6bafade97c566a
created: 2024-06-16 17:06:08.609508629+00:00
modified: 2024-03-27 10:45:52.500191986+00:00
metadata: {"tags":["javascript","react"]}
body:
  Controlled components relate to how you use forms in React.

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

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

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

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

  # Controlled components

  Controlled components relate to how you use forms in React.

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

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

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


path: zk/Create_Mongo_database.md
sortable_path: zkCreate_Mongo_database.md
title: Creating a MongoDB database
lead: First create a directory for the database and set permissions:
checksum: a56970bff12ebf7528c38b17562308601f88cd30e75003021a128d7cfcee43ac
created: 2024-06-16 17:06:08.613468221+00:00
modified: 2024-06-15 09:59:15.773144522+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
body:
  First create a directory for the database and set permissions:

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

  Then start the Mongo daemon

  ```bash
  mongod
  ```

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

  ## MongoDB Compass

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

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

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Creating a MongoDB database

  First create a directory for the database and set permissions:

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

  Then start the Mongo daemon

  ```bash
  mongod
  ```

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

  ## MongoDB Compass

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

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


path: zk/Creating_a_Mongo_schema_and_model.md
sortable_path: zkCreating_a_Mongo_schema_and_model.md
title: Creating a schema and model
lead: ## Schema
checksum: 8d1a9ab7816f21fb90420c49d1e20350e44e054dd06f880e69970db173517a4b
created: 2024-06-16 17:06:08.62560156+00:00
modified: 2024-06-15 10:03:20.357575648+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
body:
  ## Schema

  In order start adding
  [collections and documents](MongoDB_Introduction.md) to our database,
  we use Mongoose's **schema** structure. (This is specific to Mongoose and is not
  a structure that is a part of Mongo in general.)

  We use a schema to define the shape of documents in a MongoDB collection. To do
  this we instantiate an instance of the Mongoose `Schema` class and set our
  properties:

  ### Creating a schema

  ```js
  const courseSchema = new mongoose.Schema({
    name: { type: String, required: true, minlength: 5, maxlength: 255 },
    author: String,
    tags: [String],
    data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
    isPublished: Boolean,
  });
  ```

  > This is similar to declaring a type or interface in TypeScript

  #### Available data types

  The following data types are available:

  - `String`
  - `Number`
  - `Boolean`
  - `Array`
  - `Date`
  - `Buffer`
  - `ObjectID` (for UUIDs)

  > Note that we set our validation criteria as the second property for each
  > schema value. There is more info info on validation in a
  > [separate entry](Validating_Mongoose_schemas.md);

  ## Models

  Once we have established our schema we can then create a **model** of it. A
  model is basically a class representation of the interface we define in the
  schema:

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

  Now we can start adding specific courses as documents to our collection. We do
  this by referring to the model, i.e.

  ```js
  const course = new Course({
    name: "Node.js Course",
    author: "Ozzy Osbourne",
    tags: ["node", "backend"],
    isPublished: true,
  });
  ```

  ![](/img/mongoose-hierarchy.svg)

  ## Outcome

  Having created a database, connected to it with Mongoose, and created a model we
  will see our collection reflected in Compass:

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

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Creating a schema and model

  ## Schema

  In order start adding
  [collections and documents](MongoDB_Introduction.md) to our database,
  we use Mongoose's **schema** structure. (This is specific to Mongoose and is not
  a structure that is a part of Mongo in general.)

  We use a schema to define the shape of documents in a MongoDB collection. To do
  this we instantiate an instance of the Mongoose `Schema` class and set our
  properties:

  ### Creating a schema

  ```js
  const courseSchema = new mongoose.Schema({
    name: { type: String, required: true, minlength: 5, maxlength: 255 },
    author: String,
    tags: [String],
    data: { type: Date, default: Date.now }, // if unspecified, entry will default to current date
    isPublished: Boolean,
  });
  ```

  > This is similar to declaring a type or interface in TypeScript

  #### Available data types

  The following data types are available:

  - `String`
  - `Number`
  - `Boolean`
  - `Array`
  - `Date`
  - `Buffer`
  - `ObjectID` (for UUIDs)

  > Note that we set our validation criteria as the second property for each
  > schema value. There is more info info on validation in a
  > [separate entry](Validating_Mongoose_schemas.md);

  ## Models

  Once we have established our schema we can then create a **model** of it. A
  model is basically a class representation of the interface we define in the
  schema:

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

  Now we can start adding specific courses as documents to our collection. We do
  this by referring to the model, i.e.

  ```js
  const course = new Course({
    name: "Node.js Course",
    author: "Ozzy Osbourne",
    tags: ["node", "backend"],
    isPublished: true,
  });
  ```

  ![](/img/mongoose-hierarchy.svg)

  ## Outcome

  Having created a database, connected to it with Mongoose, and created a model we
  will see our collection reflected in Compass:

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


path: zk/Custom_React_hook_examples.md
sortable_path: zkCustom_React_hook_examples.md
title: Custom hook examples
lead: ## Determine viewport width
checksum: 9b615de532028e7bc353d190dec415144439d7fbf9432311fa8b2121f3ac65c9
created: 2024-06-16 17:06:08.646830362+00:00
modified: 2024-06-15 10:07:55.872513534+00:00
metadata: {"tags":["javascript","react"]}
body:
  ## Determine viewport width

  ### Hook

  ```js
  // useViewportWidth.js
  import { useEffect, useState } from "react";

  export default function (viewportWidth) {
    const [matchesViewportWidth, setMatchesViewportWidth] = useState(false);

    useEffect(() => {
      const handleResize = () =>
        window.innerWidth < viewportWidth
          ? setMatchesViewportWidth(true)
          : setMatchesViewportWidth(false);

      window.addEventListener("resize", handleResize);

      // Call on initialization to determine initial width
      handleResize();

      // Clean-up listener to prevent memory leaks
      return () => window.removeEventListener("resize", handleResize);
    }, [viewportWidth]);

    return matchesViewportWidth;
  }
  ```

  ### Unit test

  ```js
  import useViewportWidth from "./useViewportWidth";
  import { fireEvent } from "@testing-library/react";
  import { act } from "react-dom/test-utils";
  import { renderHook } from "@testing-library/react-hooks";

  describe("useViewportWidth", () => {
    it("returns `true` when window resized to mobile viewport width", () => {
      // Arrange
      const { result } = renderHook(() => useViewportWidth(768));

      // Act
      act(() => {
        window.innerWidth = 500;
        fireEvent(window, new Event("resize"));
      });

      // Assert
      expect(result.current).toBe(true);
    });

    it("returns `false` when window resized to width greater than mobile viewport", () => {
      // Arrange
      const { result } = renderHook(() => useViewportWidth(768));

      // Act
      act(() => {
        window.innerWidth = 1058;
        fireEvent(window, new Event("resize"));
      });

      // Assert
      expect(result.current).toBe(false);
    });
  })``;
  ```

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

  # Custom hook examples

  ## Determine viewport width

  ### Hook

  ```js
  // useViewportWidth.js
  import { useEffect, useState } from "react";

  export default function (viewportWidth) {
    const [matchesViewportWidth, setMatchesViewportWidth] = useState(false);

    useEffect(() => {
      const handleResize = () =>
        window.innerWidth < viewportWidth
          ? setMatchesViewportWidth(true)
          : setMatchesViewportWidth(false);

      window.addEventListener("resize", handleResize);

      // Call on initialization to determine initial width
      handleResize();

      // Clean-up listener to prevent memory leaks
      return () => window.removeEventListener("resize", handleResize);
    }, [viewportWidth]);

    return matchesViewportWidth;
  }
  ```

  ### Unit test

  ```js
  import useViewportWidth from "./useViewportWidth";
  import { fireEvent } from "@testing-library/react";
  import { act } from "react-dom/test-utils";
  import { renderHook } from "@testing-library/react-hooks";

  describe("useViewportWidth", () => {
    it("returns `true` when window resized to mobile viewport width", () => {
      // Arrange
      const { result } = renderHook(() => useViewportWidth(768));

      // Act
      act(() => {
        window.innerWidth = 500;
        fireEvent(window, new Event("resize"));
      });

      // Assert
      expect(result.current).toBe(true);
    });

    it("returns `false` when window resized to width greater than mobile viewport", () => {
      // Arrange
      const { result } = renderHook(() => useViewportWidth(768));

      // Act
      act(() => {
        window.innerWidth = 1058;
        fireEvent(window, new Event("resize"));
      });

      // Assert
      expect(result.current).toBe(false);
    });
  })``;
  ```


path: zk/Custom_types_in_TypeScript.md
sortable_path: zkCustom_types_in_TypeScript.md
title: Custom types
checksum: a31b1826fb6403da8b4a14f78beff6d2cc7d8b419f90d09d50660904af44a159
created: 2024-06-16 17:06:08.651591046+00:00
modified: 2024-03-27 10:45:52.500191986+00:00
metadata: {"tags":["typescript"]}
lead:
  Objects and [classes](Classes.md) are where TypeScript becomes most useful and
  powerful. In TypeScript, objects and classes are by definition custom types.

body:
  Objects and [classes](Classes.md) are where TypeScript becomes most useful and
  powerful. In TypeScript, objects and classes are by definition custom types.

  When typing objects, you do not write the types alongside the actual data as you
  would with primitive types, classes and functions. Instead you write a custom
  type which is a type-annotated object. This is then applied to the object or
  class, where you create instances that **match the shape** of the custom
  declaration.

  So say we have this object:

  ```js
  const age = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  We could write this as type with the following:

  ```ts
  let Age: {
    name: string;
    yearOfBirth: number;
    currentYear: number;
    ageNow: () => number;
  };
  ```

  (We use `:` because we are declaring a type not intialising a value of the
  type.)

  We could now re-write the first `age` object as an object of type `Age` :

  ```tsx
  let thomas: typeof Age;

  thomas = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  In practice, defining the type and then asserting that a new variable is of this
  type and then initialising it is rather long-winded. It is better practice to
  simplify the process by creating a **type alias**.

  ```tsx
  type Age = {
    name: string;
    yearOfBirth: number;
    currentYear: number;
    ageNow(): number; // we type the method on the basis of the value it returns
  };
  ```

  We could then create objects based on this:

  ```tsx
  const thomas: Age = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  Note that we pass in `:Age` as our type declaration, using the custom type in
  the same way as we would use `:string` or `number[]` . We can now use this
  custom type as a type annotation anywhere we use type annotations; it can be
  used exactly the same way as a primitive type in our code.

  `Age` is an alias for the type that `thomas` conforms to.

  The benefit is that TS will correct you if:

  - attempt to assign a type to a value that does not match the custom type
    declaration (for instance: assigning a string value to a property you have
    typed as number)
  - attempt to add a property that is not specified in the custom type declaration

  Although you can subsequently _extend_ the custom type (detailed below).

  ## Duck typing

  > Types are defined by the collection of their properties not their name.

  Typescript's implementation of types is as a **structural type system**, which
  contrasts with a nominal type system. This is often referred to colloquially as
  'duck typing': _if it looks like a duck, walks like a duck, and sounds like a
  duck, it probably is a duck_.

  With custom (object types) this means that the following expression of an object
  of type `Age` doesn't generate an error, TS is satisfied that the shapes of each
  match.

  ```tsx
  const martha = {
    name: "Martha",
    yearOfBirth: 1997,
    currentYear: 2021,
    gender: "female",
  };

  const addition: Age = martha;
  ```

  But if we tried to add this extra property whilst defining `martha` as an
  instance of the custom type `Age` , we would get an error:

  ```tsx
  const martha: Age = {
    name: "Martha",
    yearOfBirth: 1997,
    currentYear: 2021,
    gender: "female",
  };
  ```

  ```
  Type '{ name: string; yearOfBirth: number; currentYear: number; ageNow: () => number; gender: string; }' is not assignable to type 'Age'. **Object literal may only specify known properties, and 'gender' does not exist in type 'Age'.**
  ```

  It means that even though in the following, the variable `point` is never
  declared to be of the type `Point` , it matches the shape of the custom type. As
  the structural integrity is maintained, it can be passed to the function without
  error.

  ```tsx
  interface Point {
    x: number;
    y: number;
  }

  function logPoint(p: Point) {
    console.log(`${p.x}, ${p.y}`);
  }

  // logs "12, 26"
  const point = { x: 12, y: 26 };
  logPoint(point);
  ```

  Shape matching only requires a subset of the object's fields to match:

  ```tsx
  const point3 = { x: 12, y: 26, z: 89 };
  logPoint(point3); // logs "12, 26"

  const rect = { x: 33, y: 3, width: 30, height: 80 };
  logPoint(rect);
  ```

  ## Interfaces

  For most purposes the keywords `type` and `interface` are interchangeable in
  TypeScript.

  (The main difference that I have encountered is that Angular specifies that
  interfaces should be used over types, but this is because it is class-based and
  object oriented).

  For me, the main decider is that Angular favours `interface` over `type`. The TS
  handbook recommends using the `type` keyword over `interface`.

  An interface is concept that crosses over from strict OOP and it doesn't quite
  apply to interfaces in TS because an interface is a declaration of a class's
  functions alone, not its data (i.e properties).

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

  # Custom types

  Objects and [classes](Classes.md) are where TypeScript becomes most useful and
  powerful. In TypeScript, objects and classes are by definition custom types.

  When typing objects, you do not write the types alongside the actual data as you
  would with primitive types, classes and functions. Instead you write a custom
  type which is a type-annotated object. This is then applied to the object or
  class, where you create instances that **match the shape** of the custom
  declaration.

  So say we have this object:

  ```js
  const age = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  We could write this as type with the following:

  ```ts
  let Age: {
    name: string;
    yearOfBirth: number;
    currentYear: number;
    ageNow: () => number;
  };
  ```

  (We use `:` because we are declaring a type not intialising a value of the
  type.)

  We could now re-write the first `age` object as an object of type `Age` :

  ```tsx
  let thomas: typeof Age;

  thomas = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  In practice, defining the type and then asserting that a new variable is of this
  type and then initialising it is rather long-winded. It is better practice to
  simplify the process by creating a **type alias**.

  ```tsx
  type Age = {
    name: string;
    yearOfBirth: number;
    currentYear: number;
    ageNow(): number; // we type the method on the basis of the value it returns
  };
  ```

  We could then create objects based on this:

  ```tsx
  const thomas: Age = {
    name: "Thomas",
    yearOfBirth: 1988,
    currentYear: 2021,
    ageNow: function () {
      return this.currentYear - this.yearOfBirth;
    },
  };
  ```

  Note that we pass in `:Age` as our type declaration, using the custom type in
  the same way as we would use `:string` or `number[]` . We can now use this
  custom type as a type annotation anywhere we use type annotations; it can be
  used exactly the same way as a primitive type in our code.

  `Age` is an alias for the type that `thomas` conforms to.

  The benefit is that TS will correct you if:

  - attempt to assign a type to a value that does not match the custom type
    declaration (for instance: assigning a string value to a property you have
    typed as number)
  - attempt to add a property that is not specified in the custom type declaration

  Although you can subsequently _extend_ the custom type (detailed below).

  ## Duck typing

  > Types are defined by the collection of their properties not their name.

  Typescript's implementation of types is as a **structural type system**, which
  contrasts with a nominal type system. This is often referred to colloquially as
  'duck typing': _if it looks like a duck, walks like a duck, and sounds like a
  duck, it probably is a duck_.

  With custom (object types) this means that the following expression of an object
  of type `Age` doesn't generate an error, TS is satisfied that the shapes of each
  match.

  ```tsx
  const martha = {
    name: "Martha",
    yearOfBirth: 1997,
    currentYear: 2021,
    gender: "female",
  };

  const addition: Age = martha;
  ```

  But if we tried to add this extra property whilst defining `martha` as an
  instance of the custom type `Age` , we would get an error:

  ```tsx
  const martha: Age = {
    name: "Martha",
    yearOfBirth: 1997,
    currentYear: 2021,
    gender: "female",
  };
  ```

  ```
  Type '{ name: string; yearOfBirth: number; currentYear: number; ageNow: () => number; gender: string; }' is not assignable to type 'Age'. **Object literal may only specify known properties, and 'gender' does not exist in type 'Age'.**
  ```

  It means that even though in the following, the variable `point` is never
  declared to be of the type `Point` , it matches the shape of the custom type. As
  the structural integrity is maintained, it can be passed to the function without
  error.

  ```tsx
  interface Point {
    x: number;
    y: number;
  }

  function logPoint(p: Point) {
    console.log(`${p.x}, ${p.y}`);
  }

  // logs "12, 26"
  const point = { x: 12, y: 26 };
  logPoint(point);
  ```

  Shape matching only requires a subset of the object's fields to match:

  ```tsx
  const point3 = { x: 12, y: 26, z: 89 };
  logPoint(point3); // logs "12, 26"

  const rect = { x: 33, y: 3, width: 30, height: 80 };
  logPoint(rect);
  ```

  ## Interfaces

  For most purposes the keywords `type` and `interface` are interchangeable in
  TypeScript.

  (The main difference that I have encountered is that Angular specifies that
  interfaces should be used over types, but this is because it is class-based and
  object oriented).

  For me, the main decider is that Angular favours `interface` over `type`. The TS
  handbook recommends using the `type` keyword over `interface`.

  An interface is concept that crosses over from strict OOP and it doesn't quite
  apply to interfaces in TS because an interface is a declaration of a class's
  functions alone, not its data (i.e properties).


path: zk/Deleting_Mongo_documents.md
sortable_path: zkDeleting_Mongo_documents.md
title: MongoDB: deleting a document from a collection
checksum: d05980b37454803a7e8901255fd6e8fb49cd60535a15ff7927220667bd19b4f6
created: 2024-06-16 17:06:08.674899879+00:00
modified: 2024-06-15 10:00:07.447419012+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
lead:
  ```js
  async function deleteCourse(id) {
    const result = await Course.deleteOne({ id: id });
    console.log(result);
  }
  ```

body:
  ```js
  async function deleteCourse(id) {
    const result = await Course.deleteOne({ id: id });
    console.log(result);
  }
  ```

  Use `findByIdAndRemove([id])` if you want to return the value that is deleted.

  If we were to pass a query object that matches multiple documents in the
  database to `deleteOne` it would only delete the first document returned. To
  delete all use `deleteMany`.

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # MongoDB: deleting a document from a collection

  ```js
  async function deleteCourse(id) {
    const result = await Course.deleteOne({ id: id });
    console.log(result);
  }
  ```

  Use `findByIdAndRemove([id])` if you want to return the value that is deleted.

  If we were to pass a query object that matches multiple documents in the
  database to `deleteOne` it would only delete the first document returned. To
  delete all use `deleteMany`.


path: zk/Forms_in_React.md
sortable_path: zkForms_in_React.md
title: Forms using hooks
checksum: cc03c143d64a475e9141718c7a5ba8853cc79336b8e8bfb2aec36cfac5776c82
created: 2024-06-16 17:06:08.831593401+00:00
modified: 2024-06-15 10:15:53.249753487+00:00
metadata: {"tags":["javascript","react"]}
lead:
  With hooks, form processing is exactly the same as
  [classes](Forms_in_React.md) in terms of the overall
  methodology, but the syntax is slightly different as a result of the `useState`
  hook.

body:
  With hooks, form processing is exactly the same as
  [classes](Forms_in_React.md) in terms of the overall
  methodology, but the syntax is slightly different as a result of the `useState`
  hook.

  >

  ## Basic approach

  Instead of using `this.state` and `this.setState` . We just have the `useState`
  hook. But the controlled component principle is the same. Let's say we have a
  simple email input:

  ```jsx
  const [email, setEmail] = useState("");
  ```

  As this is a form, the state change is going to be the result of user input. So
  we need to prep our form to enable this.

  ```html
  <input type="text" value="{email}" onChange="{setEmail}" />
  ```

  Now we just need to make good on the `setEmail` method we declared when we
  initialised the state:

  ```jsx
  const handleChange = (event) => {
    setEmail(event.target.value);
  };
  ```

  ### Applied example

  Here is an applied example of the above approach for a form that has three input
  fields. This component outputs the inputs as JSON on submit:

  ```jsx

  function FormHook() {
    const [email, setEmail] = useState("");
    const [phone, setPhone] = useState("");
    const [age, setAge] = useState("");
    const [formOutput, setFormOutput] = useState("Form output");

    const handleSubmit = (event) => {
      event.preventDefault();
      setFormOutput(
        JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
      );
    };
  	return (
  		<form onSubmit={handleSubmit}>
  			<input type="text" value={email} onChange={(event) => setEmail(event.target.value)}>
  			<input type="text" value={phone} onChange={(event) => setPhone(event.target.value)}>
  			<input type="number" value={age} onChange={(event) => setAge(event.target.value)}>
  			<button type="submit">Submit</button>
  		</form>
  	)
  };
  ```

  ## More complex forms

  The above is fine if you only have one form with a couple of inputs. But if you
  are managing multiple forms or forms with a complex array of inputs, you would
  need to create `useState` declaration for every single input with a custom
  `onChange` event for each one which is repetitious and not very clean.

  So instead of this, just like with class-based controlled components, we use the
  `name` HTML attribute to distinguish each input and create a generic `onChange`
  function that distinguishes each separate input by destructuring a key, value
  object using the `name`.

  ```jsx
  <form onSubmit={handleSubmit}>
  			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
  			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
  			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
  			<button type="submit">Submit</button>
  </form>
  ```

  ```jsx
  const initialState = {
    email: "",
    phone: "",
    age: "",
  };

  const [formValues, setFormValues] = useState(initialState);

  const handleChange = (event) => {
    const { name, value } = event.target;
    setFormValues({ ...formValues, [name]: value });
  };
  ```

  There are three parts:

  1. First we create the initial state.
  2. Next we store this initial state as the variable in the `useState`
     initialisation: `formValues` . We also provide a method `setFormValues` which
     will be used by the change handler to log the user's inputs.
  3. Finally we create the function that will log the user changes. First we use
     object destructuring on the change event to enable us to retrieve the `name`
     and `value` attributes of the HTML inputs in the component. Then we use
     spread syntax to say that for each input pair, retrieve its value, using the
     destructured `name` variable as the key.

  ### Applied example

  Below I have updated the previous context to this time reflect the new,
  abstracted logic:

  ```jsx
  function FormHookAbstracted() {
    const initialState = {
      email: "",
      phone: "",
      age: "",
    };
  	const [formValues, setFormValues] = useState(initialState);
  	const handleChange = (event) => {
      const { name, value } = event.target;
      setFormValues({ ...formValues, [name]: value });
    };
    const handleSubmit = (event) => {
      event.preventDefault();
      setFormOutput(
        JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
      );
    };
  	return (
  		<form onSubmit={handleSubmit}>
  			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
  			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
  			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
  			<button type="submit">Submit</button>
  		</form>
  	)
  };
  export default FormHookAbstracted;
  ```

  Note that instead of individual variables `email` , `phone`, `age` , this
  approach returns a single object `formValues` . We could therefore access the
  individual values with e.g `[formValues.email](formvalues.email)` .

  As it is an object, it makes resetting to the original state very easy, viz:

  ```jsx
  const handleReset = () => {
    Object.values(formValues).map((x) => setFormValues(initialState));
  };
  ```

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

  # Forms using hooks

  With hooks, form processing is exactly the same as
  [classes](Forms_in_React.md) in terms of the overall
  methodology, but the syntax is slightly different as a result of the `useState`
  hook.

  >

  ## Basic approach

  Instead of using `this.state` and `this.setState` . We just have the `useState`
  hook. But the controlled component principle is the same. Let's say we have a
  simple email input:

  ```jsx
  const [email, setEmail] = useState("");
  ```

  As this is a form, the state change is going to be the result of user input. So
  we need to prep our form to enable this.

  ```html
  <input type="text" value="{email}" onChange="{setEmail}" />
  ```

  Now we just need to make good on the `setEmail` method we declared when we
  initialised the state:

  ```jsx
  const handleChange = (event) => {
    setEmail(event.target.value);
  };
  ```

  ### Applied example

  Here is an applied example of the above approach for a form that has three input
  fields. This component outputs the inputs as JSON on submit:

  ```jsx

  function FormHook() {
    const [email, setEmail] = useState("");
    const [phone, setPhone] = useState("");
    const [age, setAge] = useState("");
    const [formOutput, setFormOutput] = useState("Form output");

    const handleSubmit = (event) => {
      event.preventDefault();
      setFormOutput(
        JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
      );
    };
  	return (
  		<form onSubmit={handleSubmit}>
  			<input type="text" value={email} onChange={(event) => setEmail(event.target.value)}>
  			<input type="text" value={phone} onChange={(event) => setPhone(event.target.value)}>
  			<input type="number" value={age} onChange={(event) => setAge(event.target.value)}>
  			<button type="submit">Submit</button>
  		</form>
  	)
  };
  ```

  ## More complex forms

  The above is fine if you only have one form with a couple of inputs. But if you
  are managing multiple forms or forms with a complex array of inputs, you would
  need to create `useState` declaration for every single input with a custom
  `onChange` event for each one which is repetitious and not very clean.

  So instead of this, just like with class-based controlled components, we use the
  `name` HTML attribute to distinguish each input and create a generic `onChange`
  function that distinguishes each separate input by destructuring a key, value
  object using the `name`.

  ```jsx
  <form onSubmit={handleSubmit}>
  			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
  			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
  			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
  			<button type="submit">Submit</button>
  </form>
  ```

  ```jsx
  const initialState = {
    email: "",
    phone: "",
    age: "",
  };

  const [formValues, setFormValues] = useState(initialState);

  const handleChange = (event) => {
    const { name, value } = event.target;
    setFormValues({ ...formValues, [name]: value });
  };
  ```

  There are three parts:

  1. First we create the initial state.
  2. Next we store this initial state as the variable in the `useState`
     initialisation: `formValues` . We also provide a method `setFormValues` which
     will be used by the change handler to log the user's inputs.
  3. Finally we create the function that will log the user changes. First we use
     object destructuring on the change event to enable us to retrieve the `name`
     and `value` attributes of the HTML inputs in the component. Then we use
     spread syntax to say that for each input pair, retrieve its value, using the
     destructured `name` variable as the key.

  ### Applied example

  Below I have updated the previous context to this time reflect the new,
  abstracted logic:

  ```jsx
  function FormHookAbstracted() {
    const initialState = {
      email: "",
      phone: "",
      age: "",
    };
  	const [formValues, setFormValues] = useState(initialState);
  	const handleChange = (event) => {
      const { name, value } = event.target;
      setFormValues({ ...formValues, [name]: value });
    };
    const handleSubmit = (event) => {
      event.preventDefault();
      setFormOutput(
        JSON.stringify({ email: email, phone: phone, age: age }, null, 2)
      );
    };
  	return (
  		<form onSubmit={handleSubmit}>
  			<input type="text" name="email" value={formValues.email} onChange={handleChange}>
  			<input type="text" name="phone" value={formValues.phone} onChange={handleChange}>
  			<input type="number" name="age" value={formValues.age} onChange={handleChange}>
  			<button type="submit">Submit</button>
  		</form>
  	)
  };
  export default FormHookAbstracted;
  ```

  Note that instead of individual variables `email` , `phone`, `age` , this
  approach returns a single object `formValues` . We could therefore access the
  individual values with e.g `[formValues.email](formvalues.email)` .

  As it is an object, it makes resetting to the original state very easy, viz:

  ```jsx
  const handleReset = () => {
    Object.values(formValues).map((x) => setFormValues(initialState));
  };
  ```


path: zk/Importing_MongoDB_data.md
sortable_path: zkImporting_MongoDB_data.md
title: Importing data to MongoDB
checksum: 677b579e14fd2d752e80d93d1b76f3f2d113a7454f3689917dc8a11c9b4564cd
created: 2024-06-16 17:06:08.843775026+00:00
modified: 2024-06-15 10:03:04.113949676+00:00
metadata: {"tags":["mongo-db","node-js","databases"]}
lead:
  We can use the command line to import data into a Mongo database. We can also
  combine the importing of data with the creation of a database:

body:
  We can use the command line to import data into a Mongo database. We can also
  combine the importing of data with the creation of a database:

  ```bash
  mongoimport --db [preexisting_or_new_database name] --collection [collection_name] --file sourcedata.json --jsonArray
  ```

  We use `--jsonArray` to indicate the format of the data we are importing.

  Once this has executed, the data will be visible in Compass.

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - databases
  ---

  # Importing data to MongoDB

  We can use the command line to import data into a Mongo database. We can also
  combine the importing of data with the creation of a database:

  ```bash
  mongoimport --db [preexisting_or_new_database name] --collection [collection_name] --file sourcedata.json --jsonArray
  ```

  We use `--jsonArray` to indicate the format of the data we are importing.

  Once this has executed, the data will be visible in Compass.


path: zk/Iterating_in_React.md
sortable_path: zkIterating_in_React.md
title: Iterating through data
checksum: a417bdd27a8eaa5408dcb27982df7ef2466161fa88eeacb315e39b99b39ad4d2
created: 2024-06-16 17:06:08.849817632+00:00
modified: 2024-06-15 10:16:02.066608067+00:00
metadata: {"tags":["javascript","react"]}
lead:
  As React follows the **functional programming paradigm** and state versioning,
  looping is not the recommended way of engineering repeated processes since it
  presupposes pre-existing state. Instead React relies on the functional methods
  of modern JavaScript such as `map` , `filter` , `reduce` to output the values of
  iterative data structures.

body:
  As React follows the **functional programming paradigm** and state versioning,
  looping is not the recommended way of engineering repeated processes since it
  presupposes pre-existing state. Instead React relies on the functional methods
  of modern JavaScript such as `map` , `filter` , `reduce` to output the values of
  iterative data structures.

  Instead of mutating the state of a reference type, these methods are
  'non-destructive': they create a new array that meets the requirements set in
  the particular method. These newly created arrays and objects therefore form the
  basis of the state versioning, because each new array that is engendered, is a
  new state configuration.

  ## The `key` attribute

  The `key` attribute is a special React attribute that should be added to the
  elements of any listed content (i.e numbered lists, unordered lists, `select`
  options etc; basically anything rendered that comes about through mapping arrays
  and objects).

  This enables React to monitor the state of the list: which items have changed,
  been added, or removed.

  The best way to pick a key is to use a string that uniquely identifies a list
  item among its siblings.

  For instance, using our earlier `numbers` array, assuming each number is unique,
  we could use the number itself as the key:

  ```jsx
  const numbers = [1, 2, 3, 4, 5];
  const listItems = numbers.map((number) => (
    <li key={number.toString()}> {number}</li>
  ));
  ```

  > Keys have to be unique to the individual element and not shared by any other
  > sibling. But they do not need to be globally unique. You could use the same
  > `key` name in another array list.

  > Keys should be string types, not other data types. You can use the
  > `.toString()` method to ensure this is the case.

  If you can't find a unique basis for naming a series of keys, you can use the
  `index` value of the `Array.map` function. This should only be used if the order
  of the items doesn't change. An example:

  ```jsx
  class List extends React.Component {
    render() {
      const demoArr = ["cat", "dog", "mouse"];
      return (
          <ul>
            {demoArr.map((x, index) => (
              <li key={index}>{x}</li>
            ))}
          </ul>
        </div>
      );
    }
  }
  ```

  ## Demonstration

  ### Source data

  ```jsx
  const blogData = [
    {
      id: 1,
      date: "2020-11-15",
          shortByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
      longByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
      image: blogImage,
    },
    {
      id: 2,
      date: "2020-08-11",
          shortByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
      longByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
      image: blogImage,
    },
  ];
  ```

  ### Child component

  ```jsx
  export default function BlogPreviewCard(props) {
    return (
      <Card>
        <CardMedia image={props.image} />
        <CardContent>
          <Typography>{props.date}</Typography>
          <Typography>{props.title}</Typography>
          <Typography>{props.shortByline}</Typography>
        </CardContent>
        <CardActions>
          <Button>Read</Button>
        </CardActions>
      </Card>
    );
  }
  ```

  ### Iteration

  ```jsx
  // This uses the Material-UI grid component

  import BlogPreviewCard from "../components/BlogPreviewCard"
  import blogData from "../data/blogData

  export default function BlogPreviewSet() {
    return (
      <Grid>
        {blogDummyData.map((data, index) => (
          <Grid key={index}>
            <BlogPreviewCard key={index} {...data} />
          </Grid>
        ))}
      </Grid>
    )
  }
  ```

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

  # Iterating through data

  As React follows the **functional programming paradigm** and state versioning,
  looping is not the recommended way of engineering repeated processes since it
  presupposes pre-existing state. Instead React relies on the functional methods
  of modern JavaScript such as `map` , `filter` , `reduce` to output the values of
  iterative data structures.

  Instead of mutating the state of a reference type, these methods are
  'non-destructive': they create a new array that meets the requirements set in
  the particular method. These newly created arrays and objects therefore form the
  basis of the state versioning, because each new array that is engendered, is a
  new state configuration.

  ## The `key` attribute

  The `key` attribute is a special React attribute that should be added to the
  elements of any listed content (i.e numbered lists, unordered lists, `select`
  options etc; basically anything rendered that comes about through mapping arrays
  and objects).

  This enables React to monitor the state of the list: which items have changed,
  been added, or removed.

  The best way to pick a key is to use a string that uniquely identifies a list
  item among its siblings.

  For instance, using our earlier `numbers` array, assuming each number is unique,
  we could use the number itself as the key:

  ```jsx
  const numbers = [1, 2, 3, 4, 5];
  const listItems = numbers.map((number) => (
    <li key={number.toString()}> {number}</li>
  ));
  ```

  > Keys have to be unique to the individual element and not shared by any other
  > sibling. But they do not need to be globally unique. You could use the same
  > `key` name in another array list.

  > Keys should be string types, not other data types. You can use the
  > `.toString()` method to ensure this is the case.

  If you can't find a unique basis for naming a series of keys, you can use the
  `index` value of the `Array.map` function. This should only be used if the order
  of the items doesn't change. An example:

  ```jsx
  class List extends React.Component {
    render() {
      const demoArr = ["cat", "dog", "mouse"];
      return (
          <ul>
            {demoArr.map((x, index) => (
              <li key={index}>{x}</li>
            ))}
          </ul>
        </div>
      );
    }
  }
  ```

  ## Demonstration

  ### Source data

  ```jsx
  const blogData = [
    {
      id: 1,
      date: "2020-11-15",
          shortByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
      longByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
      image: blogImage,
    },
    {
      id: 2,
      date: "2020-08-11",
          shortByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ",
      longByline:
        "Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.",
      image: blogImage,
    },
  ];
  ```

  ### Child component

  ```jsx
  export default function BlogPreviewCard(props) {
    return (
      <Card>
        <CardMedia image={props.image} />
        <CardContent>
          <Typography>{props.date}</Typography>
          <Typography>{props.title}</Typography>
          <Typography>{props.shortByline}</Typography>
        </CardContent>
        <CardActions>
          <Button>Read</Button>
        </CardActions>
      </Card>
    );
  }
  ```

  ### Iteration

  ```jsx
  // This uses the Material-UI grid component

  import BlogPreviewCard from "../components/BlogPreviewCard"
  import blogData from "../data/blogData

  export default function BlogPreviewSet() {
    return (
      <Grid>
        {blogDummyData.map((data, index) => (
          <Grid key={index}>
            <BlogPreviewCard key={index} {...data} />
          </Grid>
        ))}
      </Grid>
    )
  }
  ```


path: zk/Memoization_in_React.md
sortable_path: zkMemoization_in_React.md
title: Memoization with useCallback and useMemo
lead: ## Rationale
checksum: aa5a1396de6830c65cebe440419eb402597ac57d198d06fa5c5fe6cea81ab4f9
created: 2024-06-16 17:06:08.981303866+00:00
modified: 2024-06-15 10:16:35.867324488+00:00
metadata: {"tags":["javascript","react"]}
body:
  ## Rationale

  In the lifecycle of a component, React re-renders the component when an update
  is made. When React checks for any changes in a component, it may detect an
  unintended or unexpected change due to how JavaScript handles equality and
  shallow comparisons. This change in the React application will cause it to
  re-render unnecessarily.

  Additionally, if that re-rendering is an expensive operation, like a long for
  loop, it can hurt performance. Expensive operations can be costly in either
  time, memory, or processing. In addition to potential technical issues, this may
  lead to poor user experience.

  If one part re-renders, it re-renders the entire component tree. `useCallback`
  and `useMemo` can be used reduce this performance impact.

  ## useCallback

  The `useCallback` hook is used to wrap functions. It tells React to not
  re-create a wrapped function when a component re-renders, unless any of the
  useCallback's dependencies change.

  `useCallback` returns a memoized version of the callback function it is passed.
  This means that the function object returned from useCallback will be the same
  between re-renders.

  Remember that in JavaScript, functions are objects and components are functions.
  As a result, every time a component containing a function re-renders, it create
  a new instance of the function in memory.

  > Given the same dependency value, the `useCallback` hook returns the same
  > function instance between renderings (aka memoization).

  This said, for small functions that are not intensive, it doesn't really matter
  if they are not memoized.

  ### Syntax

  A standard case of this would be a function that runs on a button click, for
  instance when sending data from a form to a server. In the example below there
  is quite a lot going on, and most of it is independent of the actual UI-cycle of
  the component.

  ```jsx
  const handleSubmit = useCallback(
    async (formValues) => {
      setPendSaveConfig(true);
      const payload = new GenerateConfig({
        workflowId: project_id,
        blockId: blockId,
        config: formValues,
      });
      axios
        .post(`${process.env.REACT_APP_ENDPOINT}/save-block-config`, payload)
        .then((res) => console.log(res))
        .finally(() => setPendSaveConfig(false))
        .catch((err) => console.error(err));
    },
    [blockId, project_id]
  );
  ```

  Note that the syntax is similar to [React_useEffect](React_useEffect.md): there is a
  dependency array. The effect is the same: the function contained within
  `useCallback` will only re-rendered if one of these dependencies changes.
  However (see next section) the function will run in its memoized form on every
  click.

  ### Reference versus result

  `useCallback` only memoizes the function _object_ (the reference) not the value
  that is _returned_ by the function (the result).

  In the example below, the `calculatePi()` function reference will not change
  between renders but each time the click event fires, the value returned by
  `calculatePi()` will change. In other words, it will be assigned fresh memory.

  ```jsx
  function ParentComponent() {
    const onHandleClick = useCallback(() => {
      const special = calculatePi();
    });

    return <SubComponent handleClick={onHandleClick} />;
  }
  ```

  ### Use cases

  You should not apply `useCallback` in a blanket fashion, this can reduce
  performance rather than improve it. The best scenarios are:

  1. A functional component wrapped inside React.memo() accepts a function object
     prop

  2. When the function object is a dependency to other hooks, e.g.
     `useEffect(..., [callback])`

  3. When the function has some internal state, e.g. when the function is
     debounced or throttled.

  ## useMemo

  We can think of `useMemo` as a complement to `useCallback`. The main difference
  is that whilst `useCallback` memoizes the function reference, `useMemo` memoizes
  the function result; the value that is returned.

  > In memoization, the result is “remembered” when the same parameters are
  > passed-in subsequently. If we have a function compute 1 + 1, it will return 2.
  > But if it uses memoization, the next time we run 1’s through the function, it
  > won’t add them up; it will just remember the answer is 2 without executing the
  > adding function.

  Like `useCallback`, `useMemo` takes a function and an array of dependencies for
  the same reason: if one of the dependencies changes then the function will
  recalculate (and re-memoize) the result but they don't the same memoized value
  will be returned.

  As with `useCallback`, `useMemo` is best applied to complex functions that are
  computationally expensive, it shouldn't be used indiscriminately.

  It should not be used with asynchronous functions, in these instances,
  `useEffect` would be a better choice.

  ### Syntax

  ```jsx
  const List = React.useMemo(
    () =>
      listOfItems.map((item) => ({
        ...item,
        itemProp1: expensiveFunction(props.first),
        itemProp2: anotherPriceyFunction(props.second),
      })),
    [listOfItems]
  );
  ```

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

  # Memoization with useCallback and useMemo

  ## Rationale

  In the lifecycle of a component, React re-renders the component when an update
  is made. When React checks for any changes in a component, it may detect an
  unintended or unexpected change due to how JavaScript handles equality and
  shallow comparisons. This change in the React application will cause it to
  re-render unnecessarily.

  Additionally, if that re-rendering is an expensive operation, like a long for
  loop, it can hurt performance. Expensive operations can be costly in either
  time, memory, or processing. In addition to potential technical issues, this may
  lead to poor user experience.

  If one part re-renders, it re-renders the entire component tree. `useCallback`
  and `useMemo` can be used reduce this performance impact.

  ## useCallback

  The `useCallback` hook is used to wrap functions. It tells React to not
  re-create a wrapped function when a component re-renders, unless any of the
  useCallback's dependencies change.

  `useCallback` returns a memoized version of the callback function it is passed.
  This means that the function object returned from useCallback will be the same
  between re-renders.

  Remember that in JavaScript, functions are objects and components are functions.
  As a result, every time a component containing a function re-renders, it create
  a new instance of the function in memory.

  > Given the same dependency value, the `useCallback` hook returns the same
  > function instance between renderings (aka memoization).

  This said, for small functions that are not intensive, it doesn't really matter
  if they are not memoized.

  ### Syntax

  A standard case of this would be a function that runs on a button click, for
  instance when sending data from a form to a server. In the example below there
  is quite a lot going on, and most of it is independent of the actual UI-cycle of
  the component.

  ```jsx
  const handleSubmit = useCallback(
    async (formValues) => {
      setPendSaveConfig(true);
      const payload = new GenerateConfig({
        workflowId: project_id,
        blockId: blockId,
        config: formValues,
      });
      axios
        .post(`${process.env.REACT_APP_ENDPOINT}/save-block-config`, payload)
        .then((res) => console.log(res))
        .finally(() => setPendSaveConfig(false))
        .catch((err) => console.error(err));
    },
    [blockId, project_id]
  );
  ```

  Note that the syntax is similar to [React_useEffect](React_useEffect.md): there is a
  dependency array. The effect is the same: the function contained within
  `useCallback` will only re-rendered if one of these dependencies changes.
  However (see next section) the function will run in its memoized form on every
  click.

  ### Reference versus result

  `useCallback` only memoizes the function _object_ (the reference) not the value
  that is _returned_ by the function (the result).

  In the example below, the `calculatePi()` function reference will not change
  between renders but each time the click event fires, the value returned by
  `calculatePi()` will change. In other words, it will be assigned fresh memory.

  ```jsx
  function ParentComponent() {
    const onHandleClick = useCallback(() => {
      const special = calculatePi();
    });

    return <SubComponent handleClick={onHandleClick} />;
  }
  ```

  ### Use cases

  You should not apply `useCallback` in a blanket fashion, this can reduce
  performance rather than improve it. The best scenarios are:

  1. A functional component wrapped inside React.memo() accepts a function object
     prop

  2. When the function object is a dependency to other hooks, e.g.
     `useEffect(..., [callback])`

  3. When the function has some internal state, e.g. when the function is
     debounced or throttled.

  ## useMemo

  We can think of `useMemo` as a complement to `useCallback`. The main difference
  is that whilst `useCallback` memoizes the function reference, `useMemo` memoizes
  the function result; the value that is returned.

  > In memoization, the result is “remembered” when the same parameters are
  > passed-in subsequently. If we have a function compute 1 + 1, it will return 2.
  > But if it uses memoization, the next time we run 1’s through the function, it
  > won’t add them up; it will just remember the answer is 2 without executing the
  > adding function.

  Like `useCallback`, `useMemo` takes a function and an array of dependencies for
  the same reason: if one of the dependencies changes then the function will
  recalculate (and re-memoize) the result but they don't the same memoized value
  will be returned.

  As with `useCallback`, `useMemo` is best applied to complex functions that are
  computationally expensive, it shouldn't be used indiscriminately.

  It should not be used with asynchronous functions, in these instances,
  `useEffect` would be a better choice.

  ### Syntax

  ```jsx
  const List = React.useMemo(
    () =>
      listOfItems.map((item) => ({
        ...item,
        itemProp1: expensiveFunction(props.first),
        itemProp2: anotherPriceyFunction(props.second),
      })),
    [listOfItems]
  );
  ```


path: zk/Modelling_relationships_in_MongoDB.md
sortable_path: zkModelling_relationships_in_MongoDB.md
title: Modelling relationships between data
checksum: c7525be2f33aacca299e720d1ac1ad731bffae9e7b52c6557609fb4a43532a0e
created: 2024-06-16 17:06:09.054377213+00:00
modified: 2024-06-15 10:03:44.821349335+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
lead:
  So far we have taken the values of a document to be simple: the `author` value
  is just a string but what if `author` was itself another collection for instance
  a collection with the proprties `age` and `publications` and the author name,
  say `Tosh Gnomay` was a document in this collection? This means we would have an
  interaction between two collections. In this entry we will look at how to work
  with interrelated collections. This is equivalent to establishing
  [joins](10_Joins.md) in a relational database.

body:
  So far we have taken the values of a document to be simple: the `author` value
  is just a string but what if `author` was itself another collection for instance
  a collection with the proprties `age` and `publications` and the author name,
  say `Tosh Gnomay` was a document in this collection? This means we would have an
  interaction between two collections. In this entry we will look at how to work
  with interrelated collections. This is equivalent to establishing
  [joins](10_Joins.md) in a relational database.

  There are two main approaches to modelling relationships between data:
  **normalisation** and **denormalisation**.

  ## Modelling relationships with normalisation: using references

  In the case of normalisation we use a UUID from one document to connect it to
  another document.

  Let's say that we have a course document as follows which is an instance of the
  `courses` collection:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "Tosh Gnomay"
  }
  ```

  And we have a document which is an instance of another type of collection called
  `authors`. One instance of it could be:

  ```js
  {
      _id: "de89w9",
      name: "Tosh Gnomay",
      courses: ["Java course", "C# course"]
  }
  ```

  Using normalisation, we would establish the relationship by using the value of
  the `_id` propety in the `courses` document as the value of the `name` property
  in the `authors` document. We would rewrite the `courses` document like so:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "de89w9"
  }
  ```

  ## Modelling relationships with denormalisation: embedding

  With denormalisation we achieve the same outcome but instead of using a
  reference we embed one value in another:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: {
          name: "Tosh Gnomay",
          courses: ["Java course", "C# course"]
      }
  }
  ```

  ## Tradeoffs: which approach to use?

  There are drawbacks and benefits with each approach.

  - One benefit of normalisation is consistency. Because we are using the UUID and
    referencing it in another document, if we make a change to the values in the
    source document, it will automatically apply to all documents that reference
    it. We make a change in one place and it is reflected everywhere.

  - Conversely, a drawback of denormalisation is that it invites inconsistency
    between documents. Embedded values can easily go out of sync with their usage
    elsewhere as you don't have a direct reference correspondence.

  - On the other hand a drawback of normalisation is performance when querying.
    Any time you have a document that references another document than this
    document also has to be retrieved. Therefore for every query you are returning
    two documents. As denormalised references embed the second document, only one
    document is being returned on each query.

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Modelling relationships between data

  So far we have taken the values of a document to be simple: the `author` value
  is just a string but what if `author` was itself another collection for instance
  a collection with the proprties `age` and `publications` and the author name,
  say `Tosh Gnomay` was a document in this collection? This means we would have an
  interaction between two collections. In this entry we will look at how to work
  with interrelated collections. This is equivalent to establishing
  [joins](10_Joins.md) in a relational database.

  There are two main approaches to modelling relationships between data:
  **normalisation** and **denormalisation**.

  ## Modelling relationships with normalisation: using references

  In the case of normalisation we use a UUID from one document to connect it to
  another document.

  Let's say that we have a course document as follows which is an instance of the
  `courses` collection:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "Tosh Gnomay"
  }
  ```

  And we have a document which is an instance of another type of collection called
  `authors`. One instance of it could be:

  ```js
  {
      _id: "de89w9",
      name: "Tosh Gnomay",
      courses: ["Java course", "C# course"]
  }
  ```

  Using normalisation, we would establish the relationship by using the value of
  the `_id` propety in the `courses` document as the value of the `name` property
  in the `authors` document. We would rewrite the `courses` document like so:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "de89w9"
  }
  ```

  ## Modelling relationships with denormalisation: embedding

  With denormalisation we achieve the same outcome but instead of using a
  reference we embed one value in another:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: {
          name: "Tosh Gnomay",
          courses: ["Java course", "C# course"]
      }
  }
  ```

  ## Tradeoffs: which approach to use?

  There are drawbacks and benefits with each approach.

  - One benefit of normalisation is consistency. Because we are using the UUID and
    referencing it in another document, if we make a change to the values in the
    source document, it will automatically apply to all documents that reference
    it. We make a change in one place and it is reflected everywhere.

  - Conversely, a drawback of denormalisation is that it invites inconsistency
    between documents. Embedded values can easily go out of sync with their usage
    elsewhere as you don't have a direct reference correspondence.

  - On the other hand a drawback of normalisation is performance when querying.
    Any time you have a document that references another document than this
    document also has to be retrieved. Therefore for every query you are returning
    two documents. As denormalised references embed the second document, only one
    document is being returned on each query.


path: zk/MongoDB_Introduction.md
sortable_path: zkMongoDB_Introduction.md
title: MongoDB: Introduction
checksum: 13cf7e8e089a48db143051dddb2c02e86449cf2858d7aa9e44ec492618a668f5
created: 2024-06-16 17:06:09.070860404+00:00
modified: 2024-06-15 10:03:10.864071307+00:00
metadata: {"tags":["mongo-db","databases"]}
lead:
  MongoDB is not a relational database system like SQL, instead it is
  document-based which means you do not neeed to design database tables and
  schema, you are simply storing data as JSON and there is no transformation of
  the data.

body:
  MongoDB is not a relational database system like SQL, instead it is
  document-based which means you do not neeed to design database tables and
  schema, you are simply storing data as JSON and there is no transformation of
  the data.

  Most of the notes on Mongo will introduce it within the context of Node.js
  backend. We will be sending Javascript objects and arrays to Mongo and returning
  them as JSON.

  ## Databases, collections, documents

  Although Mongo is not a relational database it has a structure that we can
  understand in relation to that paradigm. A **database** is obviously the overall
  structure. It comprises **collections** which are organised sets of data that
  are analagous to [tables](Relational_database_architecture.md#table)
  in RDBs. Within each collection are a series of **documents** which we can think
  of as being equivalent to [rows](Relational_database_architecture.md)
  in RDB table: units that comprise the collection.

  A document is a container comprising key-value pairs in the manner of an object.

  ![](/img/mongo-db-structure.svg)

raw_content:
  ---
  tags:
    - mongo-db
    - databases
  ---

  # MongoDB: Introduction

  MongoDB is not a relational database system like SQL, instead it is
  document-based which means you do not neeed to design database tables and
  schema, you are simply storing data as JSON and there is no transformation of
  the data.

  Most of the notes on Mongo will introduce it within the context of Node.js
  backend. We will be sending Javascript objects and arrays to Mongo and returning
  them as JSON.

  ## Databases, collections, documents

  Although Mongo is not a relational database it has a structure that we can
  understand in relation to that paradigm. A **database** is obviously the overall
  structure. It comprises **collections** which are organised sets of data that
  are analagous to [tables](Relational_database_architecture.md#table)
  in RDBs. Within each collection are a series of **documents** which we can think
  of as being equivalent to [rows](Relational_database_architecture.md)
  in RDB table: units that comprise the collection.

  A document is a container comprising key-value pairs in the manner of an object.

  ![](/img/mongo-db-structure.svg)


path: zk/Querying_a_Mongo_collection.md
sortable_path: zkQuerying_a_Mongo_collection.md
title: Query a Mongo collection with Mongoose
lead: We now have the following entries in our `courses` collection:
checksum: f4ac5106a9a718493ccba4d322bf1aff6ee105a11d648db5e50ffee8b902e7d7
created: 2024-06-16 17:06:09.223175479+00:00
modified: 2024-06-15 10:04:13.698535251+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
body:
  We now have the following entries in our `courses` collection:

  ```js
  {
    name: 'Python Course',
    author: 'Terry Ogleton',
    tags: [ 'python', 'backend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d23"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  {
    name: 'Javascript Course',
    author: 'Tosh Gnomay',
    tags: [ 'js', 'frontend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  ```

  Now we will query the collection. This capability is provided via the Mongoose
  schema class we used to create the `Course`
  [model](Create_collections_and_documents_with_Mongoose.md#models).
  We have the following methods available to use from the schema:

  - `find`
  - `findById`
  - `findByIdAndRemove`
  - `findByIdAndUpdate`
  - `findOne`
  - `findOneAndUpdate`
  - `findOneAndRemove`
  - ...

  The various `find` methods return a value that is promisified.

  ## Return values with `find`

  ```js
  async function getCourses() {
    const courses = await Course.find();
    console.log(courses);
  }
  ```

  ## Filter values returned

  This will return all the published courses where Tosh Gnomay is the author:

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    });
    console.log(courses);
  }
  ```

  This time we will filter by the same author but we will add additional
  parameters to distinguish:

  - only the first ten entries (using `.limit(10)`)
  - sort ascending by name (using `.sort({name: 1}))` , to descend we would use
    `-1`)
  - only return the properties `name` and `tags` for the item in the collection
    (using `.select({name: 1, tags: 1})`)

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    })
      .limit(10)
      .sort({ name: 1 })
      .select({ name: 1, tags: 1 });
    console.log(courses);
  }
  ```

  This returns:

  ```js
  [
    {
      _id: new ObjectId("62f4f07a875cff48827b8731"),
      name: "Java Course",
      tags: ["java", "backend"],
    },
    {
      _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
      name: "Javascript Course",
      tags: ["js", "frontend"],
    },
  ];
  ```

  > Note that the UUID is always returned, whether we specify it or not.

  ## Querying with operators

  So far when filtering we have been doing so with reference to properties that
  exist on the document's model (`author`, `isPublished` etc) and we have applied
  tranformations on the data returned (sorting, limiting the number or matches
  etc.). However we can also apply **operators** within our queries. Operators
  allow us to perform computations on the data, for example: for a given numerical
  property on an object, return the objects for which this value is within a
  certain range.

  When we apply operators we use the `$` symbol before the operator and pass the
  operator function as an object.

  The schema:

  ```
  Model.find( { property: { $operator: conditions } } )
  ```

  ### Comparison operators

  The following comparison operators are available in MongoDB:

  | Operator | Function                  |
  | -------- | ------------------------- |
  | `eq`     | Equal to                  |
  | `ne`     | Not equal to              |
  | `gt`     | Greater than              |
  | `gte`    | Greater than or less than |
  | `lt`     | Less than                 |
  | `lte`    | Less than or equal to     |
  | `in`     | In                        |
  | `nin`    | Not in                    |

  We can employ these comparators within a `.find` filter. For example let's
  imagine that our `courses` instances have a property of `price`.

  To filter course prices that are greater than or equal to 10 and less than or
  equal to 29:

  ```js
  Course.find({ price: { $gte: 10, $lte: 20 } });
  ```

  To filter course prices that are either 10, 15 or 20:

  ```js
  Course.find({ price: { $in: [10, 15, 20] } });
  ```

  ### Logical operators

  When we apply logical operators, we do not apply the query within the main
  `find` method. We use a dedicated method that corresponds to the logical
  predicate.

  For example to query by logical
  [OR](Truth-functional_connectives.md#disjunction):

  ```js
  async function getCourses() {
    const courses = await Course.find().or([
      { author: "Tosh Gnomay" },
      { isPublished: true },
    ]);
    console.log(courses);
  }
  ```

  We write each disjunct as an object representing the conditions we are filtering
  for within an array that is passed to the `.or()` method.

  The same syntax applies for conjunction.

  ### Regular expressions

  When filtering by strings we can use Regex for greater power.

  Previously we filtered by the author name:

  ```js
  .find({author: "Tosh Gnomay"})
  ```

  To demonstrate regex we could filter by names beginning with `T`:

  ```js
  .find({author: /^T*/})
  ```

  ```js
  async function getCourses() {
    const courses = await Course.find()
      .or([{ author: "Tosh Gnomay" }, { isPublished: true }])
      .count();
    console.log(courses);
  }
  ```

  This will return a number.

  ### Pagination

  We previously used the `limit()` method to control how many matches we return
  from a query. We can extend this functionality by creating pagination. This
  allows us to meter the return values into set chunks. This is used frequently
  when interacting with a database through a mediating RESTful API. For example to
  return values from endpoints such as:

  ```
  /api/courses?pageNumber=2&pageSize=10
  ```

  To do this you pass two values as query parameters

  ```js
  const pageNumber = 2;
  const pageSize = 10;

  async function getCourses() {
    const courses = await Course.find()
      .skip(pageNumber - 1 * pageSize)
      .limit(pageSize);
    console.log(courses);
  }
  ```

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Query a Mongo collection with Mongoose

  We now have the following entries in our `courses` collection:

  ```js
  {
    name: 'Python Course',
    author: 'Terry Ogleton',
    tags: [ 'python', 'backend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d23"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  {
    name: 'Javascript Course',
    author: 'Tosh Gnomay',
    tags: [ 'js', 'frontend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  ```

  Now we will query the collection. This capability is provided via the Mongoose
  schema class we used to create the `Course`
  [model](Create_collections_and_documents_with_Mongoose.md#models).
  We have the following methods available to use from the schema:

  - `find`
  - `findById`
  - `findByIdAndRemove`
  - `findByIdAndUpdate`
  - `findOne`
  - `findOneAndUpdate`
  - `findOneAndRemove`
  - ...

  The various `find` methods return a value that is promisified.

  ## Return values with `find`

  ```js
  async function getCourses() {
    const courses = await Course.find();
    console.log(courses);
  }
  ```

  ## Filter values returned

  This will return all the published courses where Tosh Gnomay is the author:

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    });
    console.log(courses);
  }
  ```

  This time we will filter by the same author but we will add additional
  parameters to distinguish:

  - only the first ten entries (using `.limit(10)`)
  - sort ascending by name (using `.sort({name: 1}))` , to descend we would use
    `-1`)
  - only return the properties `name` and `tags` for the item in the collection
    (using `.select({name: 1, tags: 1})`)

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    })
      .limit(10)
      .sort({ name: 1 })
      .select({ name: 1, tags: 1 });
    console.log(courses);
  }
  ```

  This returns:

  ```js
  [
    {
      _id: new ObjectId("62f4f07a875cff48827b8731"),
      name: "Java Course",
      tags: ["java", "backend"],
    },
    {
      _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
      name: "Javascript Course",
      tags: ["js", "frontend"],
    },
  ];
  ```

  > Note that the UUID is always returned, whether we specify it or not.

  ## Querying with operators

  So far when filtering we have been doing so with reference to properties that
  exist on the document's model (`author`, `isPublished` etc) and we have applied
  tranformations on the data returned (sorting, limiting the number or matches
  etc.). However we can also apply **operators** within our queries. Operators
  allow us to perform computations on the data, for example: for a given numerical
  property on an object, return the objects for which this value is within a
  certain range.

  When we apply operators we use the `$` symbol before the operator and pass the
  operator function as an object.

  The schema:

  ```
  Model.find( { property: { $operator: conditions } } )
  ```

  ### Comparison operators

  The following comparison operators are available in MongoDB:

  | Operator | Function                  |
  | -------- | ------------------------- |
  | `eq`     | Equal to                  |
  | `ne`     | Not equal to              |
  | `gt`     | Greater than              |
  | `gte`    | Greater than or less than |
  | `lt`     | Less than                 |
  | `lte`    | Less than or equal to     |
  | `in`     | In                        |
  | `nin`    | Not in                    |

  We can employ these comparators within a `.find` filter. For example let's
  imagine that our `courses` instances have a property of `price`.

  To filter course prices that are greater than or equal to 10 and less than or
  equal to 29:

  ```js
  Course.find({ price: { $gte: 10, $lte: 20 } });
  ```

  To filter course prices that are either 10, 15 or 20:

  ```js
  Course.find({ price: { $in: [10, 15, 20] } });
  ```

  ### Logical operators

  When we apply logical operators, we do not apply the query within the main
  `find` method. We use a dedicated method that corresponds to the logical
  predicate.

  For example to query by logical
  [OR](Truth-functional_connectives.md#disjunction):

  ```js
  async function getCourses() {
    const courses = await Course.find().or([
      { author: "Tosh Gnomay" },
      { isPublished: true },
    ]);
    console.log(courses);
  }
  ```

  We write each disjunct as an object representing the conditions we are filtering
  for within an array that is passed to the `.or()` method.

  The same syntax applies for conjunction.

  ### Regular expressions

  When filtering by strings we can use Regex for greater power.

  Previously we filtered by the author name:

  ```js
  .find({author: "Tosh Gnomay"})
  ```

  To demonstrate regex we could filter by names beginning with `T`:

  ```js
  .find({author: /^T*/})
  ```

  ```js
  async function getCourses() {
    const courses = await Course.find()
      .or([{ author: "Tosh Gnomay" }, { isPublished: true }])
      .count();
    console.log(courses);
  }
  ```

  This will return a number.

  ### Pagination

  We previously used the `limit()` method to control how many matches we return
  from a query. We can extend this functionality by creating pagination. This
  allows us to meter the return values into set chunks. This is used frequently
  when interacting with a database through a mediating RESTful API. For example to
  return values from endpoints such as:

  ```
  /api/courses?pageNumber=2&pageSize=10
  ```

  To do this you pass two values as query parameters

  ```js
  const pageNumber = 2;
  const pageSize = 10;

  async function getCourses() {
    const courses = await Course.find()
      .skip(pageNumber - 1 * pageSize)
      .limit(pageSize);
    console.log(courses);
  }
  ```


path: zk/React_Components.md
sortable_path: zkReact_Components.md
title: Components
checksum: 04a9cd1e4e18d7f291d2c48096e3d854b6072eb7a441f18682e47a0046861369
created: 2024-06-16 17:06:09.254576843+00:00
modified: 2024-03-27 10:45:52.500191986+00:00
metadata: {"tags":["typescript","react"]}
lead:
  We write functional components in the manner of a normal
  [function](Functions.md) that take
  a props argument and return a JSX element.

body:
  We write functional components in the manner of a normal
  [function](Functions.md) that take
  a props argument and return a JSX element.

  ```jsx
  interface IProps = {
    message: string;
  };
  const App = ({message}: IProps): JSX.Element => <div>{message}</div>;
  ```

  ## `React.FunctionComponent` / `React.FC`

  It used to be the case that you would type a function component like so:

  ```jsx
  const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
    <div>{message}</div>
  );
  ```

  This is now discouraged as it means the component can always accept children,
  even when you do not want this to be the case. There are several other minor
  drawerbacks but it's generally best to leave out the declaration.

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

  # Components

  We write functional components in the manner of a normal
  [function](Functions.md) that take
  a props argument and return a JSX element.

  ```jsx
  interface IProps = {
    message: string;
  };
  const App = ({message}: IProps): JSX.Element => <div>{message}</div>;
  ```

  ## `React.FunctionComponent` / `React.FC`

  It used to be the case that you would type a function component like so:

  ```jsx
  const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
    <div>{message}</div>
  );
  ```

  This is now discouraged as it means the component can always accept children,
  even when you do not want this to be the case. There are several other minor
  drawerbacks but it's generally best to leave out the declaration.


path: zk/React_errors.md
sortable_path: zkReact_errors.md
title: Errors
lead: ## State update on unmounted component
checksum: cfd6611ef29f02dc1c797220a7aa7235d5101356ad8dbe51db45b22375dd90c2
created: 2024-06-16 17:06:09.264356638+00:00
modified: 2024-06-15 10:16:35.863991084+00:00
metadata: {"tags":["javascript","react"]}
body:
  ## State update on unmounted component

  > Can't perform a React state update on an unmounted component. This is a no-op,
  > but it indicates a memory leak in your application. To fix, cancel all
  > subscriptions and asynchronous tasks in a useEffect cleanup function.

  This typically happens when you have an API request running in the background.
  Once the data is returned, React tries to update the state but the component is
  unmounted.

  As the warning suggests, this can be resolved using the cleanup parameter within
  [React_useEffect](React_useEffect.md#cleanup-functions).

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

  # Errors

  ## State update on unmounted component

  > Can't perform a React state update on an unmounted component. This is a no-op,
  > but it indicates a memory leak in your application. To fix, cancel all
  > subscriptions and asynchronous tasks in a useEffect cleanup function.

  This typically happens when you have an API request running in the background.
  Once the data is returned, React tries to update the state but the component is
  unmounted.

  As the warning suggests, this can be resolved using the cleanup parameter within
  [React_useEffect](React_useEffect.md#cleanup-functions).


path: zk/React_useContext.md
sortable_path: zkReact_useContext.md
title: useContext
checksum: 18e785c75ecf5aa0804e9a60c86298bcdcf08758a91c45326c6ae1dc5ccf90ba
created: 2024-06-16 17:06:09.27996053+00:00
modified: 2024-06-15 10:16:24.273746117+00:00
metadata: {"tags":["javascript","react"]}
lead:
  We use React's Context API to enable us to easily share stateful data between
  all levels of an application without having to use repetitious 'prop-drilling'
  at a component level.

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

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

  ## Providers and consumers

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

  The process is as follows:

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

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

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

  Le's initiate a context:

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

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

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

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

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

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

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

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

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

  ## `useContext` hook

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

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

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

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

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

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

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

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

  ## Updating context state

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

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

  # `useContext`

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

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

  ## Providers and consumers

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

  The process is as follows:

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

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

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

  Le's initiate a context:

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

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

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

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

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

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

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

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

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

  ## `useContext` hook

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

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

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

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

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

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

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

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

  ## Updating context state

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


path: zk/React_useEffect.md
sortable_path: zkReact_useEffect.md
title: useEffect
checksum: 51bb0ac90d0fe8ea36cf7558d565e1952a742fea7607da793b900f2635046711
created: 2024-06-16 17:06:09.292170726+00:00
modified: 2024-06-15 10:16:34.707300001+00:00
metadata: {"tags":["javascript","react"]}
lead:
  `useEffect` should be used for any background process that does not arise as a
  result of a user interaction or standard state change. The canonical example
  would be dispatching a request to an API to retrieve data to display in a
  component's initial render.

body:
  `useEffect` should be used for any background process that does not arise as a
  result of a user interaction or standard state change. The canonical example
  would be dispatching a request to an API to retrieve data to display in a
  component's initial render.

  `useEffect` enshrines but also simplifies the
  [lifecyle methods](Lifecycle_methods.md) that are used with
  class-based React components.

  ## Demonstration

  ```jsx
  const [workflowTitle, setWorkflowTitle] = useState("");
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchWorkflowTitle = () => {
      axios
        .post(`${process.env.REACT_APP_ENDPOINT}/load-workflows`, {
          workflow_id: project_id,
          user_id: isAuth?.userId,
        })
        .then((res) => {
          setWorkflowTitle(res?.data?.meta.name);
        })
        .finally(() => setLoading(false))
        .catch((err) => {
          console.error(err);
        });
    };
    setLoading(true);
    fetchWorkflowTitle();
  }, [project_id, isAuth]);
  ```

  In this example we fetch some data from a REST API and store the response value
  as state, which can then be accessed within our JSX template.

  ## Function placement

  In the example, the function is declared inside of the `useEffect` hook and then
  called. We do this to avoid adding the function to the dependency array, which
  we couldn't do if we defined it outside of the hook, somewhere in the component.
  If we did this, the function would run on every render by default and would be
  recalled again because of its placement in the dependency array, which leads to
  the 'too many rerenders' error.

  An alternative would be to define it outside of the component itself but this is
  difficult since it requires state from the component to run.

  ## Dependency array

  Note the array that is the second argument to `useEffect`. This is the
  **dependency array** and is how we manage the lifecycle of the side-effect.

  - After the initial call on render, the function within the `useEffect` block
    will run any time one of the dependencies update. The dependency array
    typically refers to variables that are defined within the hook but can also
    contain references to variables outside of it.

  - If you do not include the array, the effect runs on every render

  - If you pass an empty array, the effect will only run once on the initial
    render

  ## Cleanup functions

  The syntax of the `useEffect` hook also allows you to handle cleanup: something
  you want to do when the component unmounts (another example of how this hook
  recasts the traditional [lifecycle methods](Lifecycle_methods.md))
  . In addition to running on unmount, the cleanup function will run before the
  effect runs again (i.e. when it runs in response to a change in one of the
  elements of the dependency araray). This is chiefly used to prevent
  [memory leaks](Memory_leaks.md) and the
  ['update on unmounted component error'](React_errors.md#state-update-on-unmounted-component).

  You do this by having a `return` clause after the main effect. Schematically:

  ```js
  useEffect(() => {
    //  Run your effect;
    return () => {
      //   Put your cleanup function here
    };
  }, [input]);
  ```

  Here is an example of using a cleanup to cancel a subscription

  ```js
  useEffect(() => {
    let isApiSubscribed = true;
    axios.get(API).then((response) => {
      if (isApiSubscribed) {
        // handle success
      }
    });
    return () => {
      isApiSubscribed = false;
    };
  }, []);
  ```

  ## Resources

  [Understanding the React useEffect cleanup function]()

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

  # `useEffect`

  `useEffect` should be used for any background process that does not arise as a
  result of a user interaction or standard state change. The canonical example
  would be dispatching a request to an API to retrieve data to display in a
  component's initial render.

  `useEffect` enshrines but also simplifies the
  [lifecyle methods](Lifecycle_methods.md) that are used with
  class-based React components.

  ## Demonstration

  ```jsx
  const [workflowTitle, setWorkflowTitle] = useState("");
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchWorkflowTitle = () => {
      axios
        .post(`${process.env.REACT_APP_ENDPOINT}/load-workflows`, {
          workflow_id: project_id,
          user_id: isAuth?.userId,
        })
        .then((res) => {
          setWorkflowTitle(res?.data?.meta.name);
        })
        .finally(() => setLoading(false))
        .catch((err) => {
          console.error(err);
        });
    };
    setLoading(true);
    fetchWorkflowTitle();
  }, [project_id, isAuth]);
  ```

  In this example we fetch some data from a REST API and store the response value
  as state, which can then be accessed within our JSX template.

  ## Function placement

  In the example, the function is declared inside of the `useEffect` hook and then
  called. We do this to avoid adding the function to the dependency array, which
  we couldn't do if we defined it outside of the hook, somewhere in the component.
  If we did this, the function would run on every render by default and would be
  recalled again because of its placement in the dependency array, which leads to
  the 'too many rerenders' error.

  An alternative would be to define it outside of the component itself but this is
  difficult since it requires state from the component to run.

  ## Dependency array

  Note the array that is the second argument to `useEffect`. This is the
  **dependency array** and is how we manage the lifecycle of the side-effect.

  - After the initial call on render, the function within the `useEffect` block
    will run any time one of the dependencies update. The dependency array
    typically refers to variables that are defined within the hook but can also
    contain references to variables outside of it.

  - If you do not include the array, the effect runs on every render

  - If you pass an empty array, the effect will only run once on the initial
    render

  ## Cleanup functions

  The syntax of the `useEffect` hook also allows you to handle cleanup: something
  you want to do when the component unmounts (another example of how this hook
  recasts the traditional [lifecycle methods](Lifecycle_methods.md))
  . In addition to running on unmount, the cleanup function will run before the
  effect runs again (i.e. when it runs in response to a change in one of the
  elements of the dependency araray). This is chiefly used to prevent
  [memory leaks](Memory_leaks.md) and the
  ['update on unmounted component error'](React_errors.md#state-update-on-unmounted-component).

  You do this by having a `return` clause after the main effect. Schematically:

  ```js
  useEffect(() => {
    //  Run your effect;
    return () => {
      //   Put your cleanup function here
    };
  }, [input]);
  ```

  Here is an example of using a cleanup to cancel a subscription

  ```js
  useEffect(() => {
    let isApiSubscribed = true;
    axios.get(API).then((response) => {
      if (isApiSubscribed) {
        // handle success
      }
    });
    return () => {
      isApiSubscribed = false;
    };
  }, []);
  ```

  ## Resources

  [Understanding the React useEffect cleanup function]()


path: zk/React_useReducer.md
sortable_path: zkReact_useReducer.md
title: useReducer
checksum: 4600c79d0f79238fef08e60c2bc5e34d201e5ecba7070140155aef074d9e749c
created: 2024-06-16 17:06:09.316154908+00:00
modified: 2024-06-15 10:17:04.28125543+00:00
metadata: {"tags":["javascript","react"]}
lead:
  The `useReducer` hook is best used in scenarios where you are manipulating state
  in a way that is too complex for the trivial [React_useState](React_useState.md) use case.
  `useState` is best employed when you are updating a single value or toggling a
  boolean. If you are updating the state of an object or more complex data
  structure, it is often more efficient to employ `useReducer`.

body:
  The `useReducer` hook is best used in scenarios where you are manipulating state
  in a way that is too complex for the trivial [React_useState](React_useState.md) use case.
  `useState` is best employed when you are updating a single value or toggling a
  boolean. If you are updating the state of an object or more complex data
  structure, it is often more efficient to employ `useReducer`.

  This makes the code more manageable and also helps with separating state
  management from rendering.

  ## Syntax

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

  - `initialState`
    - The starting state, typically an object
  - `reducer`
    - A pure function that accepts two parameters:
      - The current state
      - An action object
    - The reducer function must update the current state (immutably) and return
      the new state
    - We can think of the reducer as working in the same manner as
      `state`/`setState` in the `useState` hook. The functional role is the same,
      it is just that the reducer offers more than one type of update.

  ### Example reducer

  ```js
  function reducer(state, action) {
    let newState;
    switch (action.type) {
      case "increase":
        newState = { counter: state.counter + 1 };
        break;
      case "descrease":
        newState = { counter: state.counter - 1 };
        break;
      default:
        throw new Error();
    }
    return newState;
  }
  ```

  In this example we are updating an object with the following shape:

  ```js
  {
      counter: 0,
  }
  ```

  This would be the `initialState` that we pass to the `useReducer` hook along
  with a reference to `reducer` above.

  To update the state we would invoke the `dispatch` function which applies one of
  the actions defined in the reducer. For example the following dispatch
  increments the counter by one:

  ```js
  dispatch({ type: "increase" });
  ```

  To view the updated value:

  ```js
  console.log(state.counter);
  ```

  ### Refining the syntax

  Because React doesn't mutate state, the reducer doesn't directly modify the
  current state in the `state` variable, it creates a new instance of the state
  object on each update.

  In the reducer example above this is achieved by declaring a variable `newState`
  that is updated by each `action` type and then returned. There is a more elegant
  way of doing this using spread syntax:

  ```js
  function reducer(state, action) {
    switch (action.type) {
      case "increase":
        return { ...state, counter: state.counter + 1 };
        break;
      case "decrease":
        return { ...state, counter: state.counter - 1 };
        break;
      default:
        throw new Error();
    }
  }
  ```

  ### Including payloads

  In the examples so far, we have updated the the state directly via the action
  type however it is also possible to pass data along with the `action.type` as
  `action.payload`.

  For example:

  ```js
  dispatch(
    {
      type: 'increase_by_payload'
      payload: 3,
    });
  ```

  Then we would update our reducer to handle this case:

  ```js
  function reducer(state, action) {
    switch (action.type) {
      ...
      case 'increase_by_payload':
      return {...state, counter: state.counter + action.payload}
      default:
        throw new Error();
    }
  }
  ```

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

  # `useReducer`

  The `useReducer` hook is best used in scenarios where you are manipulating state
  in a way that is too complex for the trivial [React_useState](React_useState.md) use case.
  `useState` is best employed when you are updating a single value or toggling a
  boolean. If you are updating the state of an object or more complex data
  structure, it is often more efficient to employ `useReducer`.

  This makes the code more manageable and also helps with separating state
  management from rendering.

  ## Syntax

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

  - `initialState`
    - The starting state, typically an object
  - `reducer`
    - A pure function that accepts two parameters:
      - The current state
      - An action object
    - The reducer function must update the current state (immutably) and return
      the new state
    - We can think of the reducer as working in the same manner as
      `state`/`setState` in the `useState` hook. The functional role is the same,
      it is just that the reducer offers more than one type of update.

  ### Example reducer

  ```js
  function reducer(state, action) {
    let newState;
    switch (action.type) {
      case "increase":
        newState = { counter: state.counter + 1 };
        break;
      case "descrease":
        newState = { counter: state.counter - 1 };
        break;
      default:
        throw new Error();
    }
    return newState;
  }
  ```

  In this example we are updating an object with the following shape:

  ```js
  {
      counter: 0,
  }
  ```

  This would be the `initialState` that we pass to the `useReducer` hook along
  with a reference to `reducer` above.

  To update the state we would invoke the `dispatch` function which applies one of
  the actions defined in the reducer. For example the following dispatch
  increments the counter by one:

  ```js
  dispatch({ type: "increase" });
  ```

  To view the updated value:

  ```js
  console.log(state.counter);
  ```

  ### Refining the syntax

  Because React doesn't mutate state, the reducer doesn't directly modify the
  current state in the `state` variable, it creates a new instance of the state
  object on each update.

  In the reducer example above this is achieved by declaring a variable `newState`
  that is updated by each `action` type and then returned. There is a more elegant
  way of doing this using spread syntax:

  ```js
  function reducer(state, action) {
    switch (action.type) {
      case "increase":
        return { ...state, counter: state.counter + 1 };
        break;
      case "decrease":
        return { ...state, counter: state.counter - 1 };
        break;
      default:
        throw new Error();
    }
  }
  ```

  ### Including payloads

  In the examples so far, we have updated the the state directly via the action
  type however it is also possible to pass data along with the `action.type` as
  `action.payload`.

  For example:

  ```js
  dispatch(
    {
      type: 'increase_by_payload'
      payload: 3,
    });
  ```

  Then we would update our reducer to handle this case:

  ```js
  function reducer(state, action) {
    switch (action.type) {
      ...
      case 'increase_by_payload':
      return {...state, counter: state.counter + action.payload}
      default:
        throw new Error();
    }
  }
  ```


path: zk/React_useState.md
sortable_path: zkReact_useState.md
title: useState
checksum: e3bc20741b5029e4be18e645b02bae622e038b3e40b6f60627620481e4a59686
created: 2024-06-16 17:06:09.331234913+00:00
modified: 2024-06-15 10:16:47.17756286+00:00
metadata: {"tags":["javascript","react"]}
lead:
  `useState` is the primary way in which React updates the application state based
  on user interaction.

body:
  `useState` is the primary way in which React updates the application state based
  on user interaction.

  - `useState` **receives**: the initial state as an argument
  - `useState` **returns**: the current state and a function that updates it

  The two items that are returned are returned as an array. We could refer to them
  with array syntax (i.e with `[0]` and `[1]` ) but it is more concise to use the
  destructuring syntax. But all that's happening is that a method belonging to the
  `React` library (i.e. `useState` ) is taking an argument (the initial state) and
  returning two values as an array of two elements. The first of these values is a
  variable, the second is a function.

  ```jsx
  (1) const [count, setCount] = useState(0);
  (2) const handleClick = () => { setCount(count + 1) };

  (3) <span>{count}</span>
  (4) <button onClick={handleClick)>Add one</button>
  ```

  - At line 1 we initialise the `useState` hook.
    - We use destructuring syntax to declare two variables
    - The first variable stores our initial state. The value of the initial state
      is an argument passed to `useState` , i.e. `0`. Do not confuse the variable
      with the value it refers to.
    - The second variable is a method that mutates the state referred to by the
      first variable into some new value, i.e. from `0` to a different integer
  - At line 3, which in reality, will be within your JSX and part of the
    `render()` block of the function, we render the initial state in the React
    DOM. This will change and be re-rendered in accordance with the state logic
  - At line 4 we have a user interface that executes the function on line 2. This
    function applies the state change represented by the second variable in the
    destructuring assignment at line 1 (`setCount` ): it mutates the initial state
    (`0`) by the value of `1'.

  > You can utilise as many `useState` declarations as your component requires.

  ## Passing variables as initial state

  We don't always have to declare the data types within the destructuring
  assignment. We can store them in variables and pass the variables to the
  destructuring assignment on `useState` . Below we do this for a function that
  mutates a string value:

  ```jsx
  const hi = "hello";
  const bye = "goodbye";

  const [initText, changeText] = useState(hi);

  <p>{initText}</p>
  <button onClick={()=>changeText(bye)}>ChangeText</button>
  ```

  ## Lazily setting initial state

  Although you will typically use a literal value or variable as your initial
  state, React provides a way for you to set this value through a function. This
  will only run once at the first render so as not to interfere with the second
  update parameter of `useState`. This is called **lazy initialisation**

  ```jsx
  const getInitialState = () => Number(window.localStorage.getItem("count"));
  const [count, setCount] = React.useState(getInitialState);
  ```

  ## Accessing previous state

  It is also possible to access the previous state via the `useState` hook. We can
  access this as a callback on the updater function.

  Let's say we have a simple counter set up like so:

  ```js
  const [count, setCount] = useState(0);
  ```

  We can access the prior value of `count` with:

  ```js
  const getPrevValue = () => setCount((prev) => console.log(prev));
  ```

  ### Naming best practise

  When destructuring the two variables from `useState`, React follows uses the
  following semantics: `[something, setSomething]` . This isn't required but it
  helps to keep everything clear, particularly the fact that the first thing
  destructured is a variable and the second is a function.

  > https://stackoverflow.com/questions/54807454/what-is-prevstate-in-reactjs

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

  # `useState`

  `useState` is the primary way in which React updates the application state based
  on user interaction.

  - `useState` **receives**: the initial state as an argument
  - `useState` **returns**: the current state and a function that updates it

  The two items that are returned are returned as an array. We could refer to them
  with array syntax (i.e with `[0]` and `[1]` ) but it is more concise to use the
  destructuring syntax. But all that's happening is that a method belonging to the
  `React` library (i.e. `useState` ) is taking an argument (the initial state) and
  returning two values as an array of two elements. The first of these values is a
  variable, the second is a function.

  ```jsx
  (1) const [count, setCount] = useState(0);
  (2) const handleClick = () => { setCount(count + 1) };

  (3) <span>{count}</span>
  (4) <button onClick={handleClick)>Add one</button>
  ```

  - At line 1 we initialise the `useState` hook.
    - We use destructuring syntax to declare two variables
    - The first variable stores our initial state. The value of the initial state
      is an argument passed to `useState` , i.e. `0`. Do not confuse the variable
      with the value it refers to.
    - The second variable is a method that mutates the state referred to by the
      first variable into some new value, i.e. from `0` to a different integer
  - At line 3, which in reality, will be within your JSX and part of the
    `render()` block of the function, we render the initial state in the React
    DOM. This will change and be re-rendered in accordance with the state logic
  - At line 4 we have a user interface that executes the function on line 2. This
    function applies the state change represented by the second variable in the
    destructuring assignment at line 1 (`setCount` ): it mutates the initial state
    (`0`) by the value of `1'.

  > You can utilise as many `useState` declarations as your component requires.

  ## Passing variables as initial state

  We don't always have to declare the data types within the destructuring
  assignment. We can store them in variables and pass the variables to the
  destructuring assignment on `useState` . Below we do this for a function that
  mutates a string value:

  ```jsx
  const hi = "hello";
  const bye = "goodbye";

  const [initText, changeText] = useState(hi);

  <p>{initText}</p>
  <button onClick={()=>changeText(bye)}>ChangeText</button>
  ```

  ## Lazily setting initial state

  Although you will typically use a literal value or variable as your initial
  state, React provides a way for you to set this value through a function. This
  will only run once at the first render so as not to interfere with the second
  update parameter of `useState`. This is called **lazy initialisation**

  ```jsx
  const getInitialState = () => Number(window.localStorage.getItem("count"));
  const [count, setCount] = React.useState(getInitialState);
  ```

  ## Accessing previous state

  It is also possible to access the previous state via the `useState` hook. We can
  access this as a callback on the updater function.

  Let's say we have a simple counter set up like so:

  ```js
  const [count, setCount] = useState(0);
  ```

  We can access the prior value of `count` with:

  ```js
  const getPrevValue = () => setCount((prev) => console.log(prev));
  ```

  ### Naming best practise

  When destructuring the two variables from `useState`, React follows uses the
  following semantics: `[something, setSomething]` . This isn't required but it
  helps to keep everything clear, particularly the fact that the first thing
  destructured is a variable and the second is a function.

  > https://stackoverflow.com/questions/54807454/what-is-prevstate-in-reactjs


path: zk/Update_a_Mongo_document.md
sortable_path: zkUpdate_a_Mongo_document.md
title: Update a MongoDB document
lead: There are two methods for updating a document
checksum: 45e294432528520811c33744708746297fb71bfdc96726da610ef0146c820ba4
created: 2024-06-16 17:06:09.560781628+00:00
modified: 2024-06-15 10:04:40.389014679+00:00
metadata: {"tags":["mongo-db","node-js","mongoose","databases"]}
body:
  There are two methods for updating a document

  - query first
  - update first

  ## Query first document update

  With this approach we first execute a
  [query](Querying_a_Mongo_collection.md) to retrieve the document we
  want to edit and then make the change. We use the `findById` method to identify
  the document by its UUID and then `set` to update specified properties on the
  document. The `set` method is one of many operators that can be used to update
  values. For example there is also built-in operators for increment, renaming,
  multiplying values.

  Query first is best used when you want to secure the update with some prior
  logic or to validate. For example you may not want to update a course if it is
  listed as published. You could use a query to determine the publish status and
  then only update the entry if it returns `isPublished: false`.

  ```js
  async function updateCourseFromQuery(id) {
    const course = await Course.findById(id);
    if (!course) return;
    course.set({
      isPublished: true,
      author: "A new author",
    });

    // Instead of an object, we could also set the updated properties individually
    course.isPublished = true;
    course.author = "Biggs Volunksire";

    const result = course.save();
    console.log(result);
  }
  ```

  ## Update first document update

  With this approach we don't bother with a prior query. We are confident that the
  update is legitimate and do not need to first determine that certain conditions
  are met.

  To do this we directly use the `update` method, not `find`:

  ```js
  async function updateCourseFromQuery(id) {
    const result = await Course.update({ _id: id });
    $set: {
      // Invoke the set operator
      author: "Terry Nutile";
      isPublished: true;
    }
    console.log(result);
  }
  ```

  This function will just return some metadata about the update. It won't by
  default return the updated value. To do this use the `findByIdAndUpdate()`
  method instead of `update`:

  ```js
  async function updateCourseFromQuery(id) {
      const course = await Course.findByIdAndUpdate(id, {
      $set: { // Invoke the set operator
          author: 'Terry Nutile'
          isPublished: true
      }, {new: true}});
      console.log(result)
  }
  ```

  If we don't add `{new: true}`, it will return the document before the update.

  ### Updating multiple documents at once

  // Add: notes on this

raw_content:
  ---
  tags:
    - mongo-db
    - node-js
    - mongoose
    - databases
  ---

  # Update a MongoDB document

  There are two methods for updating a document

  - query first
  - update first

  ## Query first document update

  With this approach we first execute a
  [query](Querying_a_Mongo_collection.md) to retrieve the document we
  want to edit and then make the change. We use the `findById` method to identify
  the document by its UUID and then `set` to update specified properties on the
  document. The `set` method is one of many operators that can be used to update
  values. For example there is also built-in operators for increment, renaming,
  multiplying values.

  Query first is best used when you want to secure the update with some prior
  logic or to validate. For example you may not want to update a course if it is
  listed as published. You could use a query to determine the publish status and
  then only update the entry if it returns `isPublished: false`.

  ```js
  async function updateCourseFromQuery(id) {
    const course = await Course.findById(id);
    if (!course) return;
    course.set({
      isPublished: true,
      author: "A new author",
    });

    // Instead of an object, we could also set the updated properties individually
    course.isPublished = true;
    course.author = "Biggs Volunksire";

    const result = course.save();
    console.log(result);
  }
  ```

  ## Update first document update

  With this approach we don't bother with a prior query. We are confident that the
  update is legitimate and do not need to first determine that certain conditions
  are met.

  To do this we directly use the `update` method, not `find`:

  ```js
  async function updateCourseFromQuery(id) {
    const result = await Course.update({ _id: id });
    $set: {
      // Invoke the set operator
      author: "Terry Nutile";
      isPublished: true;
    }
    console.log(result);
  }
  ```

  This function will just return some metadata about the update. It won't by
  default return the updated value. To do this use the `findByIdAndUpdate()`
  method instead of `update`:

  ```js
  async function updateCourseFromQuery(id) {
      const course = await Course.findByIdAndUpdate(id, {
      $set: { // Invoke the set operator
          author: 'Terry Nutile'
          isPublished: true
      }, {new: true}});
      console.log(result)
  }
  ```

  If we don't add `{new: true}`, it will return the document before the update.

  ### Updating multiple documents at once

  // Add: notes on this


path: zk/File_permissions_and_execution_in_Bash.md
sortable_path: zkFile_permissions_and_execution_in_Bash.md
title: File permissions and executables
checksum: 50e1fc39eafb745eb6749db498a4f61334b0187db7c64d6c5a7d33331eb6fb1f
created: 2024-06-16 17:37:31.22613985+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["shell"]}
lead:
  Every Unix file has a set of permissions that determine whether you can read,
  write or run (execute) the file.

body:
  Every Unix file has a set of permissions that determine whether you can read,
  write or run (execute) the file.

  ## Viewing file permissions

  In order to see file permissions within the terminal, use the `-l` or `-rfl`
  with the `ls` command. Remember this command can be applied at both the
  directory and single-file level. For example:

  ```bash
  drwxr-xr-x  7 thomas thomas 4096 Oct  2 19:22 angular-learning-lab
  drwxr-xr-x  5 thomas thomas 4096 Oct 17 18:05 code-exercises
  drwxr-xr-x  5 thomas thomas 4096 Sep  4 16:15 js-kata
  drwxr-xr-x  9 thomas thomas 4096 Sep 26 18:10 sinequanon
  drwxr-xr-x 12 thomas thomas 4096 Sep 19 17:41 thomas-bishop
  drwxr-xr-x  5 thomas thomas 4096 Sep  4 19:24 ts-kata
  ```

  ### What the output means

  The first column of the permissions output is known as the file's _mode_. The
  sequence from left to right is as follows:

  ```
  -       - - -                 - - -                 - - -
  type    user permissions      group permissions     other permissions
  ```

  <dl>
    <dt>type</dt>
    <dd>The file type. A dash just means an ordinary file. `d` means directory </dd>
   
    <dt>user permissions</dt>
    <dd>read, write or execute. A dash means 'nothing': the permissions for that slot in the set have not be assigned</dd>

    <dt>group and other</dt>
    <dd>group is obviously what anyone belonging to the current file's user group can do. Everyone else (outside of the user and the group) is covered by the other permissions, sometimes known as 'world' permissions</dd>
  </dl>

  ## Modifying permissions: `chmod`

  We use `chmod` for transferring ownership and file permissions quickly from the
  command-line.

  ### Octal notation

  `chmod` uses octal notation. Each numeral refers to a permission set. There are
  three numerals. The placement denotes the user group. From left to right this
  is:

  - user
  - group
  - everyone else.

  If you are working solo and not with group access to files, you can disregard
  assigning the other numerals, by putting zeros in as placeholders.

  [Permission codes](685254916b2642f189e6316b876e09c9)

  ### Example

  ```bash
  $ chmod -v 700 dummy.txt
  $ ls -l dummy.txt
  $ -rwx------  1 thomasbishop  staff  27 13 May 15:42 dummy.txtExample
  ```

  ### Useful options

  `-v` → verbose: tell the user what `chmod` is doing

  `-r` → work recursively, i.e apply the action to directories as well as files

  `-f` →silent: suppress most error messages

  ## Running bash files

  In most cases, especially when you are working alone, the most frequent codes
  you are going to need are 700 and 600. When shell scripting, you need to make
  your scripts executable for them to work, therefore you should always
  `chmod 700` when creating a `.sh` file.

  Then to invoke the script from the shell you simply enter:

  ```bash
  ./your-bash-script.sh
  ```

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

  # File permissions and executables

  Every Unix file has a set of permissions that determine whether you can read,
  write or run (execute) the file.

  ## Viewing file permissions

  In order to see file permissions within the terminal, use the `-l` or `-rfl`
  with the `ls` command. Remember this command can be applied at both the
  directory and single-file level. For example:

  ```bash
  drwxr-xr-x  7 thomas thomas 4096 Oct  2 19:22 angular-learning-lab
  drwxr-xr-x  5 thomas thomas 4096 Oct 17 18:05 code-exercises
  drwxr-xr-x  5 thomas thomas 4096 Sep  4 16:15 js-kata
  drwxr-xr-x  9 thomas thomas 4096 Sep 26 18:10 sinequanon
  drwxr-xr-x 12 thomas thomas 4096 Sep 19 17:41 thomas-bishop
  drwxr-xr-x  5 thomas thomas 4096 Sep  4 19:24 ts-kata
  ```

  ### What the output means

  The first column of the permissions output is known as the file's _mode_. The
  sequence from left to right is as follows:

  ```
  -       - - -                 - - -                 - - -
  type    user permissions      group permissions     other permissions
  ```

  <dl>
    <dt>type</dt>
    <dd>The file type. A dash just means an ordinary file. `d` means directory </dd>
   
    <dt>user permissions</dt>
    <dd>read, write or execute. A dash means 'nothing': the permissions for that slot in the set have not be assigned</dd>

    <dt>group and other</dt>
    <dd>group is obviously what anyone belonging to the current file's user group can do. Everyone else (outside of the user and the group) is covered by the other permissions, sometimes known as 'world' permissions</dd>
  </dl>

  ## Modifying permissions: `chmod`

  We use `chmod` for transferring ownership and file permissions quickly from the
  command-line.

  ### Octal notation

  `chmod` uses octal notation. Each numeral refers to a permission set. There are
  three numerals. The placement denotes the user group. From left to right this
  is:

  - user
  - group
  - everyone else.

  If you are working solo and not with group access to files, you can disregard
  assigning the other numerals, by putting zeros in as placeholders.

  [Permission codes](685254916b2642f189e6316b876e09c9)

  ### Example

  ```bash
  $ chmod -v 700 dummy.txt
  $ ls -l dummy.txt
  $ -rwx------  1 thomasbishop  staff  27 13 May 15:42 dummy.txtExample
  ```

  ### Useful options

  `-v` → verbose: tell the user what `chmod` is doing

  `-r` → work recursively, i.e apply the action to directories as well as files

  `-f` →silent: suppress most error messages

  ## Running bash files

  In most cases, especially when you are working alone, the most frequent codes
  you are going to need are 700 and 600. When shell scripting, you need to make
  your scripts executable for them to work, therefore you should always
  `chmod 700` when creating a `.sh` file.

  Then to invoke the script from the shell you simply enter:

  ```bash
  ./your-bash-script.sh
  ```


path: zk/Find_Bash_command.md
sortable_path: zkFind_Bash_command.md
title: find
lead:
  `find` can be used both to locate files and run operations on the files it
  finds.

checksum: 2fd50ecefe4f27677ab5f5f7c6df1e043c43b02a16eb0c7a851b71f68ac6c8e0
created: 2024-06-16 17:37:31.258516155+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["shell"]}
body:
  `find` can be used both to locate files and run operations on the files it
  finds.

  ## Main syntax

  ### No options

  Without options specified, `find` alone will return a recursive index of all the
  files in the directory from which it is run.

  ### Sub-directory

  If we pass a directory to `find` it will repeat the above process but
  specifically for that directory.

  ```bash
  $ find i3
  i3
  i3/config
  ```

  ### Filters

  We can specify flags as filters (known as 'tests' within the program).

  #### Type

  Filter by type: file or directory

  ```
  $ find -type d # return dirs only
  $ find -type f # return files only
  ```

  Within a specified directory:

  ```bash
  $ find i3 -type f
  ```

  #### Filename

  This is the most frequent use case: filter files by name with globbing.

  ```bash
  $ find -name "config"
  ./.git/config
  ./i3/config
  ```

  ```bash
  $ find -name "*.js"
  ```

  The same, but case insensitive: `iname`

  ```bash
  $ find -iname "*.JS"
  ```

  #### Path

  As above but this time includes directory names in the match. `ipath` is the
  case-insensitive version.

  ```bash
  $ find -path "utils*"
  utils.js
  utils/do-something.js
  ```

  ### Operators

  We can combine `find` commands by using logical operators: `-and`, `-or`,
  `-not`. For example:

  ```bash
  $ find -not -name "*.js" -type f
  ./app/index.html
  ./app/style.css
  ./dist/index.html
  ./dist/style.c
  ```

  Applied to a directory:

  ```bash
  find . -type -f -not -path "./.git/"
  ```

  ## Run programs against results

  Using the `exec` keyword we can run a program against the files that are
  returned from `find`.

  In this syntax we use `{}` as a placeholder for the path of the file that is
  matched. We use `;` (escaped) to indicate the end of the operation.

  ### Examples

  This script deletes the files that match the filter criteria:

  ```bash
  $ find -name "*.js" -exec rm {} \;
  ```

  This script finds all the files with the substring 'config' in their name and
  writes their file size to a file.

  ```bash
  find -name '*config*' -exec wc -c {} \; > config-sizes
  ```

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

  # `find`

  `find` can be used both to locate files and run operations on the files it
  finds.

  ## Main syntax

  ### No options

  Without options specified, `find` alone will return a recursive index of all the
  files in the directory from which it is run.

  ### Sub-directory

  If we pass a directory to `find` it will repeat the above process but
  specifically for that directory.

  ```bash
  $ find i3
  i3
  i3/config
  ```

  ### Filters

  We can specify flags as filters (known as 'tests' within the program).

  #### Type

  Filter by type: file or directory

  ```
  $ find -type d # return dirs only
  $ find -type f # return files only
  ```

  Within a specified directory:

  ```bash
  $ find i3 -type f
  ```

  #### Filename

  This is the most frequent use case: filter files by name with globbing.

  ```bash
  $ find -name "config"
  ./.git/config
  ./i3/config
  ```

  ```bash
  $ find -name "*.js"
  ```

  The same, but case insensitive: `iname`

  ```bash
  $ find -iname "*.JS"
  ```

  #### Path

  As above but this time includes directory names in the match. `ipath` is the
  case-insensitive version.

  ```bash
  $ find -path "utils*"
  utils.js
  utils/do-something.js
  ```

  ### Operators

  We can combine `find` commands by using logical operators: `-and`, `-or`,
  `-not`. For example:

  ```bash
  $ find -not -name "*.js" -type f
  ./app/index.html
  ./app/style.css
  ./dist/index.html
  ./dist/style.c
  ```

  Applied to a directory:

  ```bash
  find . -type -f -not -path "./.git/"
  ```

  ## Run programs against results

  Using the `exec` keyword we can run a program against the files that are
  returned from `find`.

  In this syntax we use `{}` as a placeholder for the path of the file that is
  matched. We use `;` (escaped) to indicate the end of the operation.

  ### Examples

  This script deletes the files that match the filter criteria:

  ```bash
  $ find -name "*.js" -exec rm {} \;
  ```

  This script finds all the files with the substring 'config' in their name and
  writes their file size to a file.

  ```bash
  find -name '*config*' -exec wc -c {} \; > config-sizes
  ```


path: zk/Format_specifiers_in_C.md
sortable_path: zkFormat_specifiers_in_C.md
title: Format specifiers in C
lead: # Format specifiers in C
checksum: b399e849f4915edacfd31655fcf1bdd69deb990ced6e870982d2dbc1c3ef1646
created: 2024-06-16 17:37:31.273546845+00:00
modified: 2024-06-16 17:08:20.153768769+00:00
body:
  # Format specifiers in C

  Format specifiers define the type of data to be printed on standard output. You
  need to use format specifiers whenever you are
  [printing-values-in-c](printing-values-in-c.md).

  | Specifier | Usage                      |
  | --------- | -------------------------- |
  | `%c`      | single character           |
  | `%s`      | string                     |
  | `%n`      | nothing                    |
  | `%d`      | integer (assuming base 10) |
  | `%f`      | float                      |
  | `%%`      | The percent sign itself    |

raw_content:
  ---
  id: 5faz2y2e
  title: Format specifiers in C
  tags:
    - C
  created: Thursday, February 29, 2024 | 17:41
  ---

  # Format specifiers in C

  Format specifiers define the type of data to be printed on standard output. You
  need to use format specifiers whenever you are
  [printing-values-in-c](printing-values-in-c.md).

  | Specifier | Usage                      |
  | --------- | -------------------------- |
  | `%c`      | single character           |
  | `%s`      | string                     |
  | `%n`      | nothing                    |
  | `%d`      | integer (assuming base 10) |
  | `%f`      | float                      |
  | `%%`      | The percent sign itself    |

metadata:
  {"created":"Thursday, February 29, 2024 | 17:41","id":"5faz2y2e","tags":["C"],"title":"Format specifiers in C"}


path: zk/Full_Node_API_example.md
sortable_path: zkFull_Node_API_example.md
title: Creating a RESTful API: Full example
checksum: c680971e4773cff184aed8b4d873cd6ee883270aac85577a1361b8d44a705755
created: 2024-06-16 17:37:31.300681957+00:00
modified: 2024-06-15 09:50:00.799410522+00:00
metadata: {"tags":["node-js","REST","APIs"]}
lead:
  ```js
  const express = require("express");
  const app = express(); // convention to name Express as the app
  const port = process.env.PORT || 3000;
  const Joi = require("joi");
  const helmet = require("helmet");
  const morgan = require("morgan");
  const courses = require("./routes/courses");

body:
  ```js
  const express = require("express");
  const app = express(); // convention to name Express as the app
  const port = process.env.PORT || 3000;
  const Joi = require("joi");
  const helmet = require("helmet");
  const morgan = require("morgan");
  const courses = require("./routes/courses");

  // Routes
  app.use("/api/courses", courses);

  // Middlewear
  app.use(express.json());
  app.use(helmet());

  const courses = [
    {
      id: 1,
      name: "First course",
    },
    {
      id: 2,
      name: "Second course",
    },
    {
      id: 3,
      name: "Third course",
    },
  ];

  if (app.get("env") === "development") {
    app.use(morgan("common"));
  }

  app.listen(port, () => console.log(`Listening on ${port}`));

  function validateCourse(course) {
    const schema = Joi.object({
      name: Joi.string().min(3).required(),
    });

    const { error } = schema.validate(course);
    return error;
  }

  /**
   *  Note that the following request handlers would not be stored in `index.js` they would be in their dedicated routing file.
   **/

  // Return all data from API
  courses.get("/", (req, res) => {
    res.send(courses);
  });

  // Return a specific value
  courses.get("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course) res.status(404).send("A course with the given ID was not found");
    res.send(course);
  });

  // Add a new course
  courses.post("/", (req, res) => {
    const schema = Joi.object({
      name: Joi.string().min(3).required(),
    });

    const { error } = schema.validate(req.body);
    if (error)
      return error.details.map((joiErr) => res.status(400).send(joiErr.message));

    const course = {
      id: courses.length + 1,
      name: req?.body.name,
    };
    courses.push(course);
    res.send(course);
  });

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

    if (!course)
      return res.status(404).send("A course with the given ID was not found");
    const { error } = validateCourse(req.body);

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

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

  // Delete a course
  courses.delete("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course)
      return res.status(404).send("A course with the given ID was not found");

    courses.indexOf(course);
    courses.splice(index, 1);

    res.send(course);
  });
  ```

raw_content:
  ---
  tags:
    - node-js
    - REST
    - APIs
  ---

  # Creating a RESTful API: Full example

  ```js
  const express = require("express");
  const app = express(); // convention to name Express as the app
  const port = process.env.PORT || 3000;
  const Joi = require("joi");
  const helmet = require("helmet");
  const morgan = require("morgan");
  const courses = require("./routes/courses");

  // Routes
  app.use("/api/courses", courses);

  // Middlewear
  app.use(express.json());
  app.use(helmet());

  const courses = [
    {
      id: 1,
      name: "First course",
    },
    {
      id: 2,
      name: "Second course",
    },
    {
      id: 3,
      name: "Third course",
    },
  ];

  if (app.get("env") === "development") {
    app.use(morgan("common"));
  }

  app.listen(port, () => console.log(`Listening on ${port}`));

  function validateCourse(course) {
    const schema = Joi.object({
      name: Joi.string().min(3).required(),
    });

    const { error } = schema.validate(course);
    return error;
  }

  /**
   *  Note that the following request handlers would not be stored in `index.js` they would be in their dedicated routing file.
   **/

  // Return all data from API
  courses.get("/", (req, res) => {
    res.send(courses);
  });

  // Return a specific value
  courses.get("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course) res.status(404).send("A course with the given ID was not found");
    res.send(course);
  });

  // Add a new course
  courses.post("/", (req, res) => {
    const schema = Joi.object({
      name: Joi.string().min(3).required(),
    });

    const { error } = schema.validate(req.body);
    if (error)
      return error.details.map((joiErr) => res.status(400).send(joiErr.message));

    const course = {
      id: courses.length + 1,
      name: req?.body.name,
    };
    courses.push(course);
    res.send(course);
  });

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

    if (!course)
      return res.status(404).send("A course with the given ID was not found");
    const { error } = validateCourse(req.body);

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

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

  // Delete a course
  courses.delete("/:id", (req, res) => {
    const course = courses.find((c) => c.id === parseInt(req.params.id));
    if (!course)
      return res.status(404).send("A course with the given ID was not found");

    courses.indexOf(course);
    courses.splice(index, 1);

    res.send(course);
  });
  ```


path: zk/Further_examples_of_TS_generics.md
sortable_path: zkFurther_examples_of_TS_generics.md
title: Further examples of generics in TypeScript
lead: ## Basic function
checksum: 02599d71a25bee261d052b3ee96b7d8605f670235fcf4d65b46eeac1344375fc
created: 2024-06-16 17:37:31.306920873+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["typescript"]}
body:
  ## Basic function

  In the code below we have a simple JavaScript function that receives a value and
  an an array as parameters. It returns a new array comprising the original array
  plus the additional value:

  ```js
  function generateArray(existingArray, newValue) {
    return [...existingArray, newValue];
  }
  ```

  Imagine that we want to ensure that each of the parameters share the same data
  type. In other words: if the function is passed a string array, the second
  parameter must also be a string. For example, it should not be the case that you
  can append a string to an array of numbers.

  Now imagine that we don't know in advance what type the value or array will be,
  we just know that the data types of the parameters must match.

  In converting the function to TypeScript, one way of overcoming our lack of
  foreknowledge would be to deploy `any`. This way it doesn't matter which types
  are passed to the function:

  ```ts
  function generateArray(existingArray: any[], newValue: any): any[] {
    return [...existingArray, newValue];
  }
  ```

  But this is no solution at all. The problem — as always with `any` — is that it
  strips our function of any type checks whatsoever and would therefore invite
  calls of form: `generateArray([1,2,3], 'lorem')`.

  Enter generics:

  ```ts
  function generateArray<T>(existingArr: T[], newValue: T): T[] {
    return [...existingArr, newValue];
  }
  ```

  Now, whilst we haven't asserted ahead of time which types will be used,
  whichever types we do pass in, must match. The function header is saying:

  - both arguments must be of the same type (represented by `T`)
  - the function will return an array of this same `T` type.

  If I then tried to run the function with unmatched types (for example
  `generateArray([1,2,3,4], true)` ) TypeScript would raise the following error:

  ```
  Argument of type 'boolean' is not assignable to parameter of type 'number'
  ```

  Note that even though the function in question does not express any preference
  for number types, given that our first parameter is a number, TypeScript knows
  that the second parameter must also be a number.

  > In the generic function we have used `T` as our placeholder for a generic type
  > as this is the convention. However there is no compunction to do so. We could
  > have used any letter or string, providing that the string is not a reserved
  > term.

  ### More advanced function

  This example demonstrates how we can use generics to reduce repetition when
  writing functions and is also a more realistic use case.

  Let's say we have two types or interfaces:

  ```tsx
  type VideoFormatUrls = {
    format720p: URL;
    format1080p: URL;
  };
  ```

  ```tsx
  type SubtitleFormatUrls = {
    english: URL;
    german: URL;
  };
  ```

  An example of an object matching these type definitions:

  ```tsx
  const videoFormats: VideoFormatUrls = {
  	format720p: https://www.format720p.co.uk,
  	format1080p: https://www.format1080p.co.uk
  }
  ```

  Imagine we wanted to be able to check whether a given film is available in a
  certain video format. We could write a function like this:

  ```tsx
  function isFormatAvailable(
    obj: VideoFormatUrls,
    format: string
  ): format is keyof VideoFormatUrls {
    return format in obj;
  }
  ```

  Now imagine that we need to do the same thing with subtitles, but given that
  `isFormatAvailable()` is typed to the `VideoFormatUrls` type we would get an
  error if we used this function for subtitles. But we also don't want to write a
  near identical function typed to `SubtitleFormatUrls` to subtitles just to
  ensure adequate type safety.

  Alternatively we could use a union type, for example:

  ```tsx
  function isFormatAvailable(
    obj: VideoFormatUrls | SubtitleFormatUrls,
    format: string
  ): format is keyof VideoFormatUrls {
    return format in obj;
  }
  ```

  But this quickly becomes unwieldy if we, for the sake of argument have a great
  many URL types that we want the function to utilise.

  This is where generics become super helpful. Here is how we would rewrite the
  function as a generic:

  ```tsx
  function isAvailable<Formats>(obj: Formats, key: string): key is keyof Formats {
    return key in obj;
  }
  ```

  We could then explicitly type our calls of this function, viz:

  ```tsx
  isFormatAvailable<SubtitleFormatUrls>(subtitles, "english");
  ```

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

  # Further examples of generics in TypeScript

  ## Basic function

  In the code below we have a simple JavaScript function that receives a value and
  an an array as parameters. It returns a new array comprising the original array
  plus the additional value:

  ```js
  function generateArray(existingArray, newValue) {
    return [...existingArray, newValue];
  }
  ```

  Imagine that we want to ensure that each of the parameters share the same data
  type. In other words: if the function is passed a string array, the second
  parameter must also be a string. For example, it should not be the case that you
  can append a string to an array of numbers.

  Now imagine that we don't know in advance what type the value or array will be,
  we just know that the data types of the parameters must match.

  In converting the function to TypeScript, one way of overcoming our lack of
  foreknowledge would be to deploy `any`. This way it doesn't matter which types
  are passed to the function:

  ```ts
  function generateArray(existingArray: any[], newValue: any): any[] {
    return [...existingArray, newValue];
  }
  ```

  But this is no solution at all. The problem — as always with `any` — is that it
  strips our function of any type checks whatsoever and would therefore invite
  calls of form: `generateArray([1,2,3], 'lorem')`.

  Enter generics:

  ```ts
  function generateArray<T>(existingArr: T[], newValue: T): T[] {
    return [...existingArr, newValue];
  }
  ```

  Now, whilst we haven't asserted ahead of time which types will be used,
  whichever types we do pass in, must match. The function header is saying:

  - both arguments must be of the same type (represented by `T`)
  - the function will return an array of this same `T` type.

  If I then tried to run the function with unmatched types (for example
  `generateArray([1,2,3,4], true)` ) TypeScript would raise the following error:

  ```
  Argument of type 'boolean' is not assignable to parameter of type 'number'
  ```

  Note that even though the function in question does not express any preference
  for number types, given that our first parameter is a number, TypeScript knows
  that the second parameter must also be a number.

  > In the generic function we have used `T` as our placeholder for a generic type
  > as this is the convention. However there is no compunction to do so. We could
  > have used any letter or string, providing that the string is not a reserved
  > term.

  ### More advanced function

  This example demonstrates how we can use generics to reduce repetition when
  writing functions and is also a more realistic use case.

  Let's say we have two types or interfaces:

  ```tsx
  type VideoFormatUrls = {
    format720p: URL;
    format1080p: URL;
  };
  ```

  ```tsx
  type SubtitleFormatUrls = {
    english: URL;
    german: URL;
  };
  ```

  An example of an object matching these type definitions:

  ```tsx
  const videoFormats: VideoFormatUrls = {
  	format720p: https://www.format720p.co.uk,
  	format1080p: https://www.format1080p.co.uk
  }
  ```

  Imagine we wanted to be able to check whether a given film is available in a
  certain video format. We could write a function like this:

  ```tsx
  function isFormatAvailable(
    obj: VideoFormatUrls,
    format: string
  ): format is keyof VideoFormatUrls {
    return format in obj;
  }
  ```

  Now imagine that we need to do the same thing with subtitles, but given that
  `isFormatAvailable()` is typed to the `VideoFormatUrls` type we would get an
  error if we used this function for subtitles. But we also don't want to write a
  near identical function typed to `SubtitleFormatUrls` to subtitles just to
  ensure adequate type safety.

  Alternatively we could use a union type, for example:

  ```tsx
  function isFormatAvailable(
    obj: VideoFormatUrls | SubtitleFormatUrls,
    format: string
  ): format is keyof VideoFormatUrls {
    return format in obj;
  }
  ```

  But this quickly becomes unwieldy if we, for the sake of argument have a great
  many URL types that we want the function to utilise.

  This is where generics become super helpful. Here is how we would rewrite the
  function as a generic:

  ```tsx
  function isAvailable<Formats>(obj: Formats, key: string): key is keyof Formats {
    return key in obj;
  }
  ```

  We could then explicitly type our calls of this function, viz:

  ```tsx
  isFormatAvailable<SubtitleFormatUrls>(subtitles, "english");
  ```


path: zk/Generics_in_TypeScript.md
sortable_path: zkGenerics_in_TypeScript.md
title: Generics
checksum: 74484845b015dd880dd9a5e01c698353617bd818b86e244c6946d64ab002a41c
created: 2024-06-16 17:37:31.311949889+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["typescript"]}
lead:
  Generics are a powerful feature in TypeScript that enables you to write reusable
  and flexible code while maintaining strong typing. With generics, you can create
  functions, classes, and interfaces that work with various types while preserving
  type information.

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

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

  ## Basic usage

  ### Functions

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

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

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

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

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

  #### Restricting the available types

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

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

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

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

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

  ## Interfaces and classes

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

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

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

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

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

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

  The following class uses the `KeyValuePair` interface:

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

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

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

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

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

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

  Here is an example of instantiating the class:

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

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

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

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

  console.log(allItems);

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

  ## Real examples

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

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

  export class GraphQlClient {
    private endpoint: string;

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

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

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

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

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

  ### VSCode extension TreeView generator

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

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

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

  # Generics

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

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

  ## Basic usage

  ### Functions

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

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

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

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

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

  #### Restricting the available types

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

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

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

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

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

  ## Interfaces and classes

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

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

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

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

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

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

  The following class uses the `KeyValuePair` interface:

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

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

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

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

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

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

  Here is an example of instantiating the class:

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

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

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

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

  console.log(allItems);

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

  ## Real examples

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

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

  export class GraphQlClient {
    private endpoint: string;

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

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

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

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

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

  ### VSCode extension TreeView generator

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

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


path: zk/Git_rebasing.md
sortable_path: zkGit_rebasing.md
title: Rebasing
checksum: be09e17373363834833d5deb64d2732b4c33199b79b14ab0e6dfd63676670f80
created: 2024-06-16 17:37:31.317458347+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/Global_object_in_NodeJS.md
sortable_path: zkGlobal_object_in_NodeJS.md
title: Global object
checksum: a833275912428951e9737156c72959670ed03b91fdbb78dac2aeb1cf52690ac3
created: 2024-06-16 17:37:31.335057071+00:00
modified: 2024-06-15 09:50:05.156161916+00:00
metadata: {"tags":["node-js"]}
lead:
  > In Node every function and variable should be scoped to a module. We should
  > not define functions and variables within the global scope.

body:
  > In Node every function and variable should be scoped to a module. We should
  > not define functions and variables within the global scope.

  - In Node the equivalent to the browser's `Window` object is `global`. The
    properties and methods that belong to this method are available anywhere in a
    program.

  - Just as we can technically write `Window.console.log()`, we can write
    `global.console.log()` however in both cases it is more sane to use the
    shorthand.

  - However if we declare a variable in this scope in browser-based JavaScript,
    this variable becomes accessible via the `Window` object and thus is
    accessible in global scope. The same is not true for Node. If you declare a
    variable at this level it will return undefined.

  - This is because of Node's modular nature. If you were to define a function
    `foo` in a module and then also define it in the global scope, when you call
    `foo`, the Node interpreter would not know which function to call. Hence it
    chooses not to recognise the global `foo`, returning undefined.

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

  # Global object

  > In Node every function and variable should be scoped to a module. We should
  > not define functions and variables within the global scope.

  - In Node the equivalent to the browser's `Window` object is `global`. The
    properties and methods that belong to this method are available anywhere in a
    program.

  - Just as we can technically write `Window.console.log()`, we can write
    `global.console.log()` however in both cases it is more sane to use the
    shorthand.

  - However if we declare a variable in this scope in browser-based JavaScript,
    this variable becomes accessible via the `Window` object and thus is
    accessible in global scope. The same is not true for Node. If you declare a
    variable at this level it will return undefined.

  - This is because of Node's modular nature. If you were to define a function
    `foo` in a module and then also define it in the global scope, when you call
    `foo`, the Node interpreter would not know which function to call. Hence it
    chooses not to recognise the global `foo`, returning undefined.


path: zk/Intersection_types_in_TypeScript.md
sortable_path: zkIntersection_types_in_TypeScript.md
title: Intersection types
checksum: f5d651d47122ae6fa8ecc204ac6dad3d06c12d1531df51dbfcbaafb1aaea5b91
created: 2024-06-16 17:37:31.351636406+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["typescript"]}
lead:
  Like union types, intersection types allow us to combine the properties of
  existing primitive and custom types to make composites.

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

  ### Creating an intersection

  Say you have the following three types:

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

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

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

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

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

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

  ```ts
  // The intersection

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

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

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

  ### Alternative method

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

  ### Benefits of intersections

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

  ## Set theory: understanding errors

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

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

  # Intersection types

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

  ### Creating an intersection

  Say you have the following three types:

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

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

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

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

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

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

  ```ts
  // The intersection

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

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

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

  ### Alternative method

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

  ### Benefits of intersections

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

  ## Set theory: understanding errors

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


path: zk/List_comprehension_in_Python.md
sortable_path: zkList_comprehension_in_Python.md
title: List comprehension
checksum: 47f1ec37b472ca033ebbdfae22ba2e8c7ac0b0943d70dcb158fa782b62e3f28f
created: 2024-06-16 17:37:31.42618326+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["python"]}
lead:
  List comprehension is a syntactic shorthand for applying a function to each
  element in a list without explicitly using loop syntax.

body:
  List comprehension is a syntactic shorthand for applying a function to each
  element in a list without explicitly using loop syntax.

  Since its introduction to the language, the same functionality has become
  achievable by using functional methods like
  [`map` and `filter`](Map_and_filter_in_Python.md),
  utilising [lambdas](Lambdas_in_Python.md)
  however list comprehension is often more straightforward and easier to read.

  ## Syntax

  Here is a basic example which applies `+ 1` to each integer in a list:

  ```python
  values = [1, 2, 4, 6, 8, 9]

  new_values = [i + 1 for i in values]
  print('new_values', new_values)
  # new_values [2, 3, 5, 7, 9, 10]
  ```

  The basic syntax is as follows:

  ```
  new_list  = [expression for each member in an iterable]
  ```

  - The _expression_ can be the member itself, a call to a method, or any other
    valid expression that returns a value. In the example above, the expression
    `i + i` adds one to each member value.

  - The _member_ is the object or value in the list or iterable. In the example
    above, the member value is _i_.

  - The _iterable_ is a list, set, dictionary or any other object that can return
    its elements one at a time. In the example above, the iterable is each value
    in `values`.

  This is a much more condensed way of achieving the same outcome with a
  traditional loop:

  ```py
  values = [1, 2, 4, 6, 8, 9]
  new_list = []
  for i in values:
    values.append(i+1)
  ```

  ### Another example

  In the following example, we apply list comprehension with a `in range` loop
  structure:

  ```py
  new_list = [i * i for i in range(10) ]
  print(new_list)
  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

  ```

  ### Adding a condition

  We can apply a conditional to a comprehension:

  ```py
  new_list = [item + 1 for item in values if item % 2 == 0]

  print('new_list:', new_list)
  # new_list: [3, 5, 7, 9]
  ```

  ### Filters

  By applying a condition (and no execution to each element) we effectively create
  a filter:

  ```py
  numbers = [1, 2, 3, 4, 4, 4]
  numbers_filtered = [i for i in numbers if i > 2]
  print(numbers_filtered)
  # [3, 4, 5]
  ```

  For comparison, the same outcome could be achieved with a filter and lambda:

  ```py
  with_filter = list(filter(lambda x: x > 2, numbers))
  print(with_filter)
  # [3, 4, 5]
  ```

  ## Set comprehension

  We can also apply comprehension to sets. The syntax is practically identical but
  the difference is the resultant data structure will not contain duplicates.

  ```py
  numbers = [1, 2, 3, 4, 4, 4]
  unique =  {i for i in numbers}
  print(unique)
  # {1,2,3,4}
  ```

  ## Dictionary comprehension

  ```py
  squares = {i: i * i for i in range(5)}
  print(squares)
  {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
  ```

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

  # List comprehension

  List comprehension is a syntactic shorthand for applying a function to each
  element in a list without explicitly using loop syntax.

  Since its introduction to the language, the same functionality has become
  achievable by using functional methods like
  [`map` and `filter`](Map_and_filter_in_Python.md),
  utilising [lambdas](Lambdas_in_Python.md)
  however list comprehension is often more straightforward and easier to read.

  ## Syntax

  Here is a basic example which applies `+ 1` to each integer in a list:

  ```python
  values = [1, 2, 4, 6, 8, 9]

  new_values = [i + 1 for i in values]
  print('new_values', new_values)
  # new_values [2, 3, 5, 7, 9, 10]
  ```

  The basic syntax is as follows:

  ```
  new_list  = [expression for each member in an iterable]
  ```

  - The _expression_ can be the member itself, a call to a method, or any other
    valid expression that returns a value. In the example above, the expression
    `i + i` adds one to each member value.

  - The _member_ is the object or value in the list or iterable. In the example
    above, the member value is _i_.

  - The _iterable_ is a list, set, dictionary or any other object that can return
    its elements one at a time. In the example above, the iterable is each value
    in `values`.

  This is a much more condensed way of achieving the same outcome with a
  traditional loop:

  ```py
  values = [1, 2, 4, 6, 8, 9]
  new_list = []
  for i in values:
    values.append(i+1)
  ```

  ### Another example

  In the following example, we apply list comprehension with a `in range` loop
  structure:

  ```py
  new_list = [i * i for i in range(10) ]
  print(new_list)
  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

  ```

  ### Adding a condition

  We can apply a conditional to a comprehension:

  ```py
  new_list = [item + 1 for item in values if item % 2 == 0]

  print('new_list:', new_list)
  # new_list: [3, 5, 7, 9]
  ```

  ### Filters

  By applying a condition (and no execution to each element) we effectively create
  a filter:

  ```py
  numbers = [1, 2, 3, 4, 4, 4]
  numbers_filtered = [i for i in numbers if i > 2]
  print(numbers_filtered)
  # [3, 4, 5]
  ```

  For comparison, the same outcome could be achieved with a filter and lambda:

  ```py
  with_filter = list(filter(lambda x: x > 2, numbers))
  print(with_filter)
  # [3, 4, 5]
  ```

  ## Set comprehension

  We can also apply comprehension to sets. The syntax is practically identical but
  the difference is the resultant data structure will not contain duplicates.

  ```py
  numbers = [1, 2, 3, 4, 4, 4]
  unique =  {i for i in numbers}
  print(unique)
  # {1,2,3,4}
  ```

  ## Dictionary comprehension

  ```py
  squares = {i: i * i for i in range(5)}
  print(squares)
  {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
  ```


