# notes

path: Logical_consistency.md
sortable_path: Logical_consistency.md
title: Logical consistency
lead: ## Informal definition
checksum: 25b31fea3e617c20721052b3fb39a4b363a687e9183bbcf5cc6abab51e4219b6
created: 2024-10-22 16:52:57.482552077+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  ## Informal definition

  A set of propositions is consistent if and only if **it is possible for all the
  members of the set to be true at the same time**. A set of propositions is
  inconsistent if and only if it is not consistent.

  ### Demonstration

  The following set of propositions form an inconsistent set:

  1. Anyone who takes astrology seriously is a lunatic.
  2. Alice is my sister and no sister of mine has a lunatic for a husband.
  3. David is Alice's husband and he read's the horoscope column every morning.
  4. Anyone who reads the horoscope column every morning takes astrology
     seriously.

  The set is inconsistent because not all of them can be true. If (1), (3), (4)
  are true, (2) cannot be. If (2), (3),(4) are true, (1) cannot be.

  ## Formal definition

  > A finite set of propositions $\Gamma$ is truth-functionally consistent if and
  > only if there is at least one truth-assignment in which all propositions of
  > $\Gamma$ are true.

  ### Informal expression

  ```
  The book is blue or the book is brown
  The book is brown
  ```

  ### Formal expression

  $$
  \{P \lor Q, Q\}
  $$

  ### Truth table

  $ \{P, Q\} $ form a consistent set because there is at least one assignment when
  both propositions are true. In fact there are two (corresponding to each
  disjunct) but one is sufficient.

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

  ## Derivation

  > In terms of logical derivation, a finite $\Gamma$ of propositions is
  > **inconsistent** in a system of derivation for propositional logic if and only
  > if a proposition of the form $P \& \lnot P$ is derivable from $\Gamma$. It is
  > **consistent** just if this is not the case.

  In other terms, if you can derive a contradiction from the set, the set is
  logically inconsistent.

  A
  [contradiction](Logical_truth_and_falsity.md#logical-falsity)
  has very important consequences for reasoning because if a set of propositions
  is inconsistent, any other proposition is derivable from it.

  ![](/img/derivation_from_contradiction.png)

  _A demonstration of the the consequences of deriving a contradiction in a
  sequence of reasoning._

  Here we want to derive some proposition $Q$. If we can derive a contradiction
  from its negation as an assumption then, by the
  [negation elimination](Negation_Elimination.md)) rule, we can
  assert $Q$. This is why contradictions should be avoided in arguments, they
  'prove' everything which, by association, undermines any particular premise you
  are trying to assert.

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

  # Logical consistency

  ## Informal definition

  A set of propositions is consistent if and only if **it is possible for all the
  members of the set to be true at the same time**. A set of propositions is
  inconsistent if and only if it is not consistent.

  ### Demonstration

  The following set of propositions form an inconsistent set:

  1. Anyone who takes astrology seriously is a lunatic.
  2. Alice is my sister and no sister of mine has a lunatic for a husband.
  3. David is Alice's husband and he read's the horoscope column every morning.
  4. Anyone who reads the horoscope column every morning takes astrology
     seriously.

  The set is inconsistent because not all of them can be true. If (1), (3), (4)
  are true, (2) cannot be. If (2), (3),(4) are true, (1) cannot be.

  ## Formal definition

  > A finite set of propositions $\Gamma$ is truth-functionally consistent if and
  > only if there is at least one truth-assignment in which all propositions of
  > $\Gamma$ are true.

  ### Informal expression

  ```
  The book is blue or the book is brown
  The book is brown
  ```

  ### Formal expression

  $$
  \{P \lor Q, Q\}
  $$

  ### Truth table

  $ \{P, Q\} $ form a consistent set because there is at least one assignment when
  both propositions are true. In fact there are two (corresponding to each
  disjunct) but one is sufficient.

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

  ## Derivation

  > In terms of logical derivation, a finite $\Gamma$ of propositions is
  > **inconsistent** in a system of derivation for propositional logic if and only
  > if a proposition of the form $P \& \lnot P$ is derivable from $\Gamma$. It is
  > **consistent** just if this is not the case.

  In other terms, if you can derive a contradiction from the set, the set is
  logically inconsistent.

  A
  [contradiction](Logical_truth_and_falsity.md#logical-falsity)
  has very important consequences for reasoning because if a set of propositions
  is inconsistent, any other proposition is derivable from it.

  ![](/img/derivation_from_contradiction.png)

  _A demonstration of the the consequences of deriving a contradiction in a
  sequence of reasoning._

  Here we want to derive some proposition $Q$. If we can derive a contradiction
  from its negation as an assumption then, by the
  [negation elimination](Negation_Elimination.md)) rule, we can
  assert $Q$. This is why contradictions should be avoided in arguments, they
  'prove' everything which, by association, undermines any particular premise you
  are trying to assert.


path: Logical_equivalence.md
sortable_path: Logical_equivalence.md
title: Logical equivalence
checksum: b08ec98b4bd43e93cacd533e9b9d0847dc5ae2454cd8d160eed3a4b7a635fb90
created: 2024-10-22 16:52:57.498611424+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["propositional-logic","logic"]}
lead:
  > Two sentences, P and Q, are truth-functionally equivalent if and only if there
  > is no truth assignment in which P is true and Q is false

body:
  > Two sentences, P and Q, are truth-functionally equivalent if and only if there
  > is no truth assignment in which P is true and Q is false

  ### Informal expression

  P: If it is raining then the pavement will be wet.

  Q: The pavement is not wet unless it is raining.

  ### Formal expression

  $$
  (P \rightarrow Q) \longleftrightarrow (\lnot P \lor Q)
  $$

  ### Truth-tables

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

  ### Derivation

  > Propositions $P$ and $Q$ are equivalent in a system of
  > [derivation](Formal%20proofs%20in%20propositional%20logic.md) for
  > propositional logic if $Q$ is derivable from $P$ and $P$ is derivable from
  > $Q$.

  Note that the property of equivalence stated in terms of derivablity above is
  identical to the derivation rule for the
  [material biconditional](Biconditional_Introduction.md):

  ![bi-intro.png](bi-intro.png)

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

  # Logical equivalence

  > Two sentences, P and Q, are truth-functionally equivalent if and only if there
  > is no truth assignment in which P is true and Q is false

  ### Informal expression

  P: If it is raining then the pavement will be wet.

  Q: The pavement is not wet unless it is raining.

  ### Formal expression

  $$
  (P \rightarrow Q) \longleftrightarrow (\lnot P \lor Q)
  $$

  ### Truth-tables

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

  ### Derivation

  > Propositions $P$ and $Q$ are equivalent in a system of
  > [derivation](Formal%20proofs%20in%20propositional%20logic.md) for
  > propositional logic if $Q$ is derivable from $P$ and $P$ is derivable from
  > $Q$.

  Note that the property of equivalence stated in terms of derivablity above is
  identical to the derivation rule for the
  [material biconditional](Biconditional_Introduction.md):

  ![bi-intro.png](bi-intro.png)


path: Logical_indeterminacy.md
sortable_path: Logical_indeterminacy.md
title: Logical indeterminacy
checksum: 32e3fa137e65eff2c6f39ea7a5fca9d67f8a160dfbe8ad1551a0c8995a001af3
created: 2024-10-22 16:52:57.512602452+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["propositional-logic","logic"]}
lead:
  The vast majority of propositions in natural and formal logical languages are
  **neither
  [logically true](Logical_truth_and_falsity.md#logical-truth)
  or
  [logically false](Logical_truth_and_falsity.md#logical-falsity)**.
  This makes sense because propositions of this form are all either tautologies or
  contradictions and as such do not express information about the state of events
  in the world. We call propositions that are neither logically true or logically
  false, **logically indeterminate** propositions.

body:
  The vast majority of propositions in natural and formal logical languages are
  **neither
  [logically true](Logical_truth_and_falsity.md#logical-truth)
  or
  [logically false](Logical_truth_and_falsity.md#logical-falsity)**.
  This makes sense because propositions of this form are all either tautologies or
  contradictions and as such do not express information about the state of events
  in the world. We call propositions that are neither logically true or logically
  false, **logically indeterminate** propositions.

  ## Informal definition

  A proposition is logically indeterminate if it is neither logically true or
  logically false. This is to say: it can be both [consistently](Consistency.md)
  asserted and consistently denied.

  For example the proposition:

  ```
  It is raining.
  ```

  May be true or false thus it can it both be asserted and denied quite
  consistently. It is true if it actually is raining and false if it actually is
  not raining. There is no logical contradiction implied by saying it is raining
  when it isn't raining, this assertion is simply false. There is a contradiction
  in saying that both states obtain. Thus the proposition:

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

  Cannot be consistently asserted as there is no possibility of the proposition
  being true. It is either raining or it isn't raining. Given the law for
  conjunction, both conjuncts must be true for the proposition as a whole to be
  true. But in the case of this proposition if one conjunct is true, the other
  must be false and vice versa, hence it is not possible for the proposition to be
  true at all. It can _only_ be false.

  Contrariwise the proposition:

  ```
  It is raining or it is not raining.
  ```

  Cannot be consistently denied as there is no possibility of it being false. It
  is either raining or not raining. Given the law for disjunction, either disjunct
  can be true to make the proposition as a whole true. Given that it is either
  raining or not raining in either scenario, the proposition as a whole will be
  true. Therefore there is no possibility of it being false, it can _only_ be
  true.

  ## Formal definition

  > A proposition P is truth-functionally indeterminate if and only if it is
  > neither truth-functionally true or truth-functionally false. should be avoided
  > in arguments, they 'prove' everything whi

  ```
  P
  ```

  ### Truth-table

  | $P$ | $P$ |
  | --- | --- |
  | T   | T   |
  | F   | F   |

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

  # Logical indeterminacy

  The vast majority of propositions in natural and formal logical languages are
  **neither
  [logically true](Logical_truth_and_falsity.md#logical-truth)
  or
  [logically false](Logical_truth_and_falsity.md#logical-falsity)**.
  This makes sense because propositions of this form are all either tautologies or
  contradictions and as such do not express information about the state of events
  in the world. We call propositions that are neither logically true or logically
  false, **logically indeterminate** propositions.

  ## Informal definition

  A proposition is logically indeterminate if it is neither logically true or
  logically false. This is to say: it can be both [consistently](Consistency.md)
  asserted and consistently denied.

  For example the proposition:

  ```
  It is raining.
  ```

  May be true or false thus it can it both be asserted and denied quite
  consistently. It is true if it actually is raining and false if it actually is
  not raining. There is no logical contradiction implied by saying it is raining
  when it isn't raining, this assertion is simply false. There is a contradiction
  in saying that both states obtain. Thus the proposition:

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

  Cannot be consistently asserted as there is no possibility of the proposition
  being true. It is either raining or it isn't raining. Given the law for
  conjunction, both conjuncts must be true for the proposition as a whole to be
  true. But in the case of this proposition if one conjunct is true, the other
  must be false and vice versa, hence it is not possible for the proposition to be
  true at all. It can _only_ be false.

  Contrariwise the proposition:

  ```
  It is raining or it is not raining.
  ```

  Cannot be consistently denied as there is no possibility of it being false. It
  is either raining or not raining. Given the law for disjunction, either disjunct
  can be true to make the proposition as a whole true. Given that it is either
  raining or not raining in either scenario, the proposition as a whole will be
  true. Therefore there is no possibility of it being false, it can _only_ be
  true.

  ## Formal definition

  > A proposition P is truth-functionally indeterminate if and only if it is
  > neither truth-functionally true or truth-functionally false. should be avoided
  > in arguments, they 'prove' everything whi

  ```
  P
  ```

  ### Truth-table

  | $P$ | $P$ |
  | --- | --- |
  | T   | T   |
  | F   | F   |


path: Logical_possibility_and_necessity.md
sortable_path: Logical_possibility_and_necessity.md
title: Logical possibility and necessity
lead: ## Logical possibility
checksum: f2b8d371f555e5b90f5e19beba80d8f0b6a488c50cc44d3ee4aca2bab05158c9
created: 2024-10-22 16:52:57.533755454+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  ## Logical possibility

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

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

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

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

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

  Some examples of contradictions:

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

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

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

  ## Logical necessity

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

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

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

  # Logical possibility and necessity

  ## Logical possibility

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

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

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

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

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

  Some examples of contradictions:

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

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

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

  ## Logical necessity

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

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


path: Logical_truth_and_falsity.md
sortable_path: Logical_truth_and_falsity.md
title: Logical truth and falsity
lead: We say of certain propositions that they are logically true or logically false.
checksum: 4a99a064e5afe470ad3eb6ae5bb245501ff8c76df7292f13e67109dd80525769
created: 2024-10-22 16:52:57.551356557+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["propositional-logic","logic"]}
body:
  We say of certain propositions that they are logically true or logically false.

  ## Logical falsity

  ### Informal definition

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

  **Demonstration**

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

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

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

  ### Formal definition

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

  ### Formal expression

  $$ P \land \lnot P $$

  ### Truth-table

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

  ## Logical truth

  ### Informal definition

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

  **Demonstration**

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

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

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

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

  ### Formal definition

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

  $$ P \lor \lnot P$$

  ### Truth-table

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

  ### Consequences

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

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

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

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

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

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

  # Logical truth and falsity

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

  ## Logical falsity

  ### Informal definition

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

  **Demonstration**

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

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

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

  ### Formal definition

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

  ### Formal expression

  $$ P \land \lnot P $$

  ### Truth-table

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

  ## Logical truth

  ### Informal definition

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

  **Demonstration**

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

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

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

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

  ### Formal definition

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

  $$ P \lor \lnot P$$

  ### Truth-table

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

  ### Consequences

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

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

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

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

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


path: Loops_in_Python.md
sortable_path: Loops_in_Python.md
title: Loops in Python
lead: ## For
checksum: ca0f453f1cd1fc7e5ac9385243923ae593595fe1ded7c3961b3a7f4396369dc1
created: 2024-10-22 16:52:57.563425017+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["python"]}
body:
  ## For

  There are three main types of `for` loop in Python and they all use the
  `for...in` clause:

  1. Traditional `for` loop with range:

     ```py
     for i in range(0, 5):
         print(i)
     ```

     This is equivalent to the following in JavaScript:

     ```js
     for (let i = 0; i <= 5: i++) {
         console.log(i)
     }
     ```

  2. `for` loop with iterable:

     ```py
     fruits = ["apple", "banana", "cherry"]
     for fruit in fruits:
         print(fruit)
     ```

  3. `for` loop with `enumerate()` function: Iterate over an iterable whilst also
     keeping track of the index of the current element:
     ```py
     for index, fruit in enumerate(fruits):
         print(f"Index {index}: {fruit}")
     ```

  ### Loop in increments greater than 1

  The following loop increments by 2 on each iteration

  ```py
  for i in range(0, 10, 2):
      print(i, ' ', end='')
  print()

  # 0  2  4  6  8
  ```

  ### Break and continue

  #### Break

  ```py
  num = int(input('Enter a number from 1-6 to check for: '))
  for i in range(0, 6):
      if i == num:
          break
      print(i, ' ')
  ```

  #### Continue

  ```py
  for i in range(0, 10):
      print(i, ' ', end='')
      if i % 2 == 1:
          continue
      print('hey its an even number')
      print('we love even numbers')
  print('Done')

  """
  0  hey its an even number
  we love even numbers
  1  2  hey its an even number
  we love even numbers
  3  4  hey its an even number
  we love even numbers
  5  6  hey its an even number
  we love even numbers
  7  8  hey its an even number
  we love even numbers
  9  Done
  """
  ```

  ## While

  ```python
  count = 0
  print('Starting')
  while count < 10:
      print(count, '', end='')
      count += 1

  print()  # not part of the while loop
  print('Done')

  """
  Starting
  0 1 2 3 4 5 6 7 8 9
  Done
  """
  ```

  > There are no `do while` loops in Python

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

  # Loops in Python

  ## For

  There are three main types of `for` loop in Python and they all use the
  `for...in` clause:

  1. Traditional `for` loop with range:

     ```py
     for i in range(0, 5):
         print(i)
     ```

     This is equivalent to the following in JavaScript:

     ```js
     for (let i = 0; i <= 5: i++) {
         console.log(i)
     }
     ```

  2. `for` loop with iterable:

     ```py
     fruits = ["apple", "banana", "cherry"]
     for fruit in fruits:
         print(fruit)
     ```

  3. `for` loop with `enumerate()` function: Iterate over an iterable whilst also
     keeping track of the index of the current element:
     ```py
     for index, fruit in enumerate(fruits):
         print(f"Index {index}: {fruit}")
     ```

  ### Loop in increments greater than 1

  The following loop increments by 2 on each iteration

  ```py
  for i in range(0, 10, 2):
      print(i, ' ', end='')
  print()

  # 0  2  4  6  8
  ```

  ### Break and continue

  #### Break

  ```py
  num = int(input('Enter a number from 1-6 to check for: '))
  for i in range(0, 6):
      if i == num:
          break
      print(i, ' ')
  ```

  #### Continue

  ```py
  for i in range(0, 10):
      print(i, ' ', end='')
      if i % 2 == 1:
          continue
      print('hey its an even number')
      print('we love even numbers')
  print('Done')

  """
  0  hey its an even number
  we love even numbers
  1  2  hey its an even number
  we love even numbers
  3  4  hey its an even number
  we love even numbers
  5  6  hey its an even number
  we love even numbers
  7  8  hey its an even number
  we love even numbers
  9  Done
  """
  ```

  ## While

  ```python
  count = 0
  print('Starting')
  while count < 10:
      print(count, '', end='')
      count += 1

  print()  # not part of the while loop
  print('Done')

  """
  Starting
  0 1 2 3 4 5 6 7 8 9
  Done
  """
  ```

  > There are no `do while` loops in Python


path: Loops_in_bash.md
sortable_path: Loops_in_bash.md
title: Loops in Bash
lead: ## Traditional for loop
checksum: 021d8bf50cddf71c62034ac838af2c11526a8a1ce9f3debec29c67a6f8150ef6
created: 2024-10-22 16:52:57.567762429+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["shell"]}
body:
  ## Traditional for loop

  ```bash
  for (( i=0; i<=5;i++  )); do
    echo $i
  done

  # 1 2 3 4 5
  ```

  ## `for..in`: loop through an array

  ```bash
  for element in "${arr[@]}"
  do
      echo "$element"
  done
  ```

  ## While loop

  > `while` loops execute while a condition is true (0)

  We can use a `while` loop as a condition in two senses:

  - execute while a given condition obtains
  - expand and execute a given command as long as the final command in the `while'
    for the command has an exit status of zero (i.e. truthy)

  Here is an exampe of using `while` in the former case:

  ```sh
  declare -i n=0
  while (( n<10 ))
  do
    echo "n:$n"
    (( n++ ))
  done
  ```

  Here is an example of using `while` in the latter case:

  ```sh
  while read line;
  do
      # something
  done < "$file_to_read"
  ```

  ## Until loop

  > `until` loops execute until a condition is false (1)

  ```sh
  declare -i m=0
  until (( m==10 )): do
    echo "m:$m"
    (( m++ ))
  done
  ```

  This gives us the same output as `n` with the while loop but here it runs so
  long as `m==10` is false. As soon as `m` is equal to 100, the condition becomes
  true and hence the loop stops.

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

  # Loops in Bash

  ## Traditional for loop

  ```bash
  for (( i=0; i<=5;i++  )); do
    echo $i
  done

  # 1 2 3 4 5
  ```

  ## `for..in`: loop through an array

  ```bash
  for element in "${arr[@]}"
  do
      echo "$element"
  done
  ```

  ## While loop

  > `while` loops execute while a condition is true (0)

  We can use a `while` loop as a condition in two senses:

  - execute while a given condition obtains
  - expand and execute a given command as long as the final command in the `while'
    for the command has an exit status of zero (i.e. truthy)

  Here is an exampe of using `while` in the former case:

  ```sh
  declare -i n=0
  while (( n<10 ))
  do
    echo "n:$n"
    (( n++ ))
  done
  ```

  Here is an example of using `while` in the latter case:

  ```sh
  while read line;
  do
      # something
  done < "$file_to_read"
  ```

  ## Until loop

  > `until` loops execute until a condition is false (1)

  ```sh
  declare -i m=0
  until (( m==10 )): do
    echo "m:$m"
    (( m++ ))
  done
  ```

  This gives us the same output as `n` with the while loop but here it runs so
  long as `m==10` is false. As soon as `m` is equal to 100, the condition becomes
  true and hence the loop stops.


path: MAC_addresses.md
sortable_path: MAC_addresses.md
title: MAC addresses
checksum: d385cd4964d14e1ef14c8f39104492844bd52abd4e3d9b6e0532bf89f721339d
created: 2024-10-22 16:52:57.571859747+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Tuesday, August 06, 2024","tags":["networks"]}
lead:
  A Media Access Control (MAC) address is a physical address in contrast to, say,
  an IP address which is logical.

body:
  A Media Access Control (MAC) address is a physical address in contrast to, say,
  an IP address which is logical.

  Each device on a [local network](./Link_Layer_of_Internet_Protocol.md) has a MAC
  as a unique identifier. It is a hardware-based, physical attribute of the
  device, typically permanently encoded onto a non-volatile memory chip attached
  to the ![network_card](Network_card.md).

  MAC addresses consist of 6 bytes (48-bits) represented as 12
  [hexadecimal_digits](Hexadecimal_number_system.md).

raw_content:
  ---
  tags: [networks]
  created: Tuesday, August 06, 2024
  ---

  # MAC addresses

  A Media Access Control (MAC) address is a physical address in contrast to, say,
  an IP address which is logical.

  Each device on a [local network](./Link_Layer_of_Internet_Protocol.md) has a MAC
  as a unique identifier. It is a hardware-based, physical attribute of the
  device, typically permanently encoded onto a non-volatile memory chip attached
  to the ![network_card](Network_card.md).

  MAC addresses consist of 6 bytes (48-bits) represented as 12
  [hexadecimal_digits](Hexadecimal_number_system.md).


path: Machine_code.md
sortable_path: Machine_code.md
title: Machine code
checksum: 7263fea79e96bbbcfefd575e9e1dee8b4d44be390d74f55f036f5ab5ae8ada7c
created: 2024-10-22 16:52:57.582615918+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
lead:
  No matter how a program was originally written, it eventually needs to execute
  on a [[CPU_architecture|CPU]] as a series of machine language instructions.

body:
  No matter how a program was originally written, it eventually needs to execute
  on a [[CPU_architecture|CPU]] as a series of machine language instructions.

  ## Example machine instruction

  The following machine instruction is an instruction that would be understood by
  an [[Instruction_set_architectures| ARM ISA]]. It moves the number `4` into the
  `r7` register:

  ```
  11100011101000000111000000000100
  ```

  This 32-bit line of binary has a series of instructions embedded within it. We
  partition each part of the sequence below, from left to right, mapping it to the
  instruction:

  | Binary sequence | Instruction          | Action                                   |
  | --------------- | -------------------- | ---------------------------------------- |
  | 1110            | condition            | always execute (unconditional)           |
  | 00              | --                   | --                                       |
  | 1               | immediate            | value is in the last 8 bits              |
  | 1101            | opcode               | `mov` : move the value                   |
  | 0               | --                   | --                                       |
  | 0000            | --                   | --                                       |
  | 0111            | destination register | destination is 0111 which means `r7`     |
  | 0000            | --                   | --                                       |
  | 00000100        | immediate value      | the binary representation of decimal '4' |

  - The blank zeros are also instructions, they are just not used in this
    instruction

  - The condition sequence tells us the instruction should run in all conditions
    not only under certain circumstances

  - The immediate bit (`1`) tells us whether the the value we are accessing is
    contained within the instruction or whether it is stored in a register. In
    this scenario `1` means the value is in the instruction. If it were `0`, the
    register where the value is located would be specified elsewhere in the
    instruction (in one of the currently blank sequences).

  - The opcode correspoons to `mov` the value.

  - THe destination register details where the value should be moved to (`r7`)

  - Finally, the immediate value is equivalent to decimal `4`

  ## Difficulty

  Binary sequences are hard to understand, even if converted to the
  [[Hexadecimal_number_system]]. We have a better way of managing operations on
  the machine level: [assembly](Assembly.md)

raw_content:
  ---
  id: iqh8
  tags:
    - binary
    - CPU
    - hardware
    - computer-architecture
  created: Monday, March 11, 2024
  ---

  # Machine code

  No matter how a program was originally written, it eventually needs to execute
  on a [[CPU_architecture|CPU]] as a series of machine language instructions.

  ## Example machine instruction

  The following machine instruction is an instruction that would be understood by
  an [[Instruction_set_architectures| ARM ISA]]. It moves the number `4` into the
  `r7` register:

  ```
  11100011101000000111000000000100
  ```

  This 32-bit line of binary has a series of instructions embedded within it. We
  partition each part of the sequence below, from left to right, mapping it to the
  instruction:

  | Binary sequence | Instruction          | Action                                   |
  | --------------- | -------------------- | ---------------------------------------- |
  | 1110            | condition            | always execute (unconditional)           |
  | 00              | --                   | --                                       |
  | 1               | immediate            | value is in the last 8 bits              |
  | 1101            | opcode               | `mov` : move the value                   |
  | 0               | --                   | --                                       |
  | 0000            | --                   | --                                       |
  | 0111            | destination register | destination is 0111 which means `r7`     |
  | 0000            | --                   | --                                       |
  | 00000100        | immediate value      | the binary representation of decimal '4' |

  - The blank zeros are also instructions, they are just not used in this
    instruction

  - The condition sequence tells us the instruction should run in all conditions
    not only under certain circumstances

  - The immediate bit (`1`) tells us whether the the value we are accessing is
    contained within the instruction or whether it is stored in a register. In
    this scenario `1` means the value is in the instruction. If it were `0`, the
    register where the value is located would be specified elsewhere in the
    instruction (in one of the currently blank sequences).

  - The opcode correspoons to `mov` the value.

  - THe destination register details where the value should be moved to (`r7`)

  - Finally, the immediate value is equivalent to decimal `4`

  ## Difficulty

  Binary sequences are hard to understand, even if converted to the
  [[Hexadecimal_number_system]]. We have a better way of managing operations on
  the machine level: [assembly](Assembly.md)

metadata:
  {"created":"Monday, March 11, 2024","id":"iqh8","tags":["binary","CPU","hardware","computer-architecture"]}


path: Magnetic_core_memory.md
sortable_path: Magnetic_core_memory.md
title: Magnetic core memory
lead: ![](../img/magnetic-core-memory.jpg)
checksum: 946a0b8cf1656b420be858bad9e76ca1c4974a70b88e00088d16b74e3055d3c4
created: 2024-10-22 16:52:57.598275535+00:00
modified: 2024-10-18 18:16:37.832744547+00:00
metadata: {"created":"Friday, September 27, 2024","tags":["computer-history","memory"]}
body:
  ![](../img/magnetic-core-memory.jpg)

  Like [Magnetic_drum_memory](Magnetic_drum_memory.md), magnetic core memory was
  faster and more reliable than [delay_line_memory](Delay_line_memory.md) and
  vacuum-tubes, and was also persistent. Thus it was used for volatile memory as
  well as storage.

  It worked as follows. Magnetic beads made of ferrite and threaded with copper
  were arranged in a crisscross grid. A bead would be placed at the overlap of two
  copper threads. This constitutes a "core".A pulse of electric current would
  magnetise/de-magnetise the cores.

  ![](../img/magnetic-core-closeup.jpg)

raw_content:
  ---
  tags: [computer-history, memory]
  created: Friday, September 27, 2024
  ---

  # Magnetic core memory

  ![](../img/magnetic-core-memory.jpg)

  Like [Magnetic_drum_memory](Magnetic_drum_memory.md), magnetic core memory was
  faster and more reliable than [delay_line_memory](Delay_line_memory.md) and
  vacuum-tubes, and was also persistent. Thus it was used for volatile memory as
  well as storage.

  It worked as follows. Magnetic beads made of ferrite and threaded with copper
  were arranged in a crisscross grid. A bead would be placed at the overlap of two
  copper threads. This constitutes a "core".A pulse of electric current would
  magnetise/de-magnetise the cores.

  ![](../img/magnetic-core-closeup.jpg)


path: Magnetic_drum_memory.md
sortable_path: Magnetic_drum_memory.md
title: Magnetic drum memory
checksum: 8ca7a01d80bbcbdcb6dca744f5a122187aa786f3c6b523a3c86f86d5ae870f01
created: 2024-10-22 16:52:57.613771878+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"created":"Tuesday, September 24, 2024","tags":["computer-history","memory"]}
lead:
  Along with the [Williams_Tube](Williams_Tube_memory.md), another early approach
  to RAM used in 1950s-1960s era of computing.

body:
  Along with the [Williams_Tube](Williams_Tube_memory.md), another early approach
  to RAM used in 1950s-1960s era of computing.

  ![Magnetic drum](../img/magnetic-drum-memory.jpg)

  A magnetic drum was a metal cylinder coated with a magnetic material. Data was
  stored by magnetising small regions on the drum's surface. The drum would rotate
  at high speeds and read/write heads were positioned along the length of the drum
  to access data.

  Seen as a improvement on Williams Tubes and
  [delay line memory](Delay_line_memory.md) but superseded by magnetic core memory
  later. It's concept lived on in harddisk drives which became the dominant form
  of secondary storage.

  It had a larger capacity than the technologies that preceded it and it was also
  non-volatile - the data would remain intact when the power was turned off.

  It was used in the [IBM 650](The_History_of_Computing_Swade.md) (1953) and
  Ferranti Mark I (1951)

raw_content:
  ---
  tags: [computer-history, memory]
  created: Tuesday, September 24, 2024
  ---

  # Magnetic drum memory

  Along with the [Williams_Tube](Williams_Tube_memory.md), another early approach
  to RAM used in 1950s-1960s era of computing.

  ![Magnetic drum](../img/magnetic-drum-memory.jpg)

  A magnetic drum was a metal cylinder coated with a magnetic material. Data was
  stored by magnetising small regions on the drum's surface. The drum would rotate
  at high speeds and read/write heads were positioned along the length of the drum
  to access data.

  Seen as a improvement on Williams Tubes and
  [delay line memory](Delay_line_memory.md) but superseded by magnetic core memory
  later. It's concept lived on in harddisk drives which became the dominant form
  of secondary storage.

  It had a larger capacity than the technologies that preceded it and it was also
  non-volatile - the data would remain intact when the power was turned off.

  It was used in the [IBM 650](The_History_of_Computing_Swade.md) (1953) and
  Ferranti Mark I (1951)


path: Magnetic_tape.md
sortable_path: Magnetic_tape.md
title: Magnetic tape
checksum: 0b07c8e2462ce875eda2c00c8e49c806621d49ad7318bbd0ef1056ad3d26a6f1
created: 2024-10-22 16:52:57.633282075+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Monday, September 23, 2024","tags":["computer-history","storage"]}
lead:
  Used for data storage in early digital computers (broadly from the
  [UNIVAC](./The_History_of_Computing_Swade.md)) era until the mini-computer era.

body:
  Used for data storage in early digital computers (broadly from the
  [UNIVAC](./The_History_of_Computing_Swade.md)) era until the mini-computer era.

  While the UNIVAC was not the first to use magnetic tape, it popularised the
  method due to its success and high profile.

  ![Magnetic tape reader in IBM computer](../img/magnetic-tape-ibm.jpeg)

  It worked as follows. The tape was a long, narrow strip of plastic coated with a
  magnetic material. Data is recorded on the the tape by magnetising tiny
  particles on its surface. It was first used in the 1920s for audio recording.

  Data is accessed in a linear, sequential manner. To reach a specific piece of
  data, you often need to wind through all the preceding data

  It was used for long term storage rather than RAM memory due to its sequential
  nature. It stored data and program instructions that would be read into the
  machine's memory. Data was also written out to magenetic tape, in order to store
  and further process results.

  It could store more data than punched cards and its sequential nature
  accommodated batch processing well. However its sequential nature meant it was
  slow at retreiving specific pieces of data as it would have to cycle through all
  the values stored on the tape.

  ![Magnetic tape stored as casette](../img/magnetic-tape-disk.jpeg)

  It developed from open-reel tapes to cartridges and cassettes. It was superseded
  by hard disk drives and solid state drives.

raw_content:
  ---
  tags: [computer-history, storage]
  created: Monday, September 23, 2024
  ---

  # Magnetic tape

  Used for data storage in early digital computers (broadly from the
  [UNIVAC](./The_History_of_Computing_Swade.md)) era until the mini-computer era.

  While the UNIVAC was not the first to use magnetic tape, it popularised the
  method due to its success and high profile.

  ![Magnetic tape reader in IBM computer](../img/magnetic-tape-ibm.jpeg)

  It worked as follows. The tape was a long, narrow strip of plastic coated with a
  magnetic material. Data is recorded on the the tape by magnetising tiny
  particles on its surface. It was first used in the 1920s for audio recording.

  Data is accessed in a linear, sequential manner. To reach a specific piece of
  data, you often need to wind through all the preceding data

  It was used for long term storage rather than RAM memory due to its sequential
  nature. It stored data and program instructions that would be read into the
  machine's memory. Data was also written out to magenetic tape, in order to store
  and further process results.

  It could store more data than punched cards and its sequential nature
  accommodated batch processing well. However its sequential nature meant it was
  slow at retreiving specific pieces of data as it would have to cycle through all
  the values stored on the tape.

  ![Magnetic tape stored as casette](../img/magnetic-tape-disk.jpeg)

  It developed from open-reel tapes to cartridges and cassettes. It was superseded
  by hard disk drives and solid state drives.


path: Mainframe_computers.md
sortable_path: Mainframe_computers.md
title: Mainframe computers
checksum: 75b912ea66c5f6b06475187d504b2c873b6d4f161c78d8aa54a9935bf2a75545
created: 2024-10-22 16:52:57.644174766+00:00
modified: 2024-10-18 18:16:47.869599104+00:00
metadata: {"created":"Friday, September 27, 2024","tags":["computer-history"]}
lead:
  A mainframe computer, also known as a "big iron" is a high performance computer
  used for resource-intensive tasks that require greater security and availability
  than smaller scale machines. They are typically used for centralised rather than
  distributed computing.

body:
  A mainframe computer, also known as a "big iron" is a high performance computer
  used for resource-intensive tasks that require greater security and availability
  than smaller scale machines. They are typically used for centralised rather than
  distributed computing.

  The heyday of mainframes was before the mini- and micro-computer revolution but
  they are still used.

  IBM remains the main manufacturer and service provider for mainframes. Example
  use cases include banks who need to process large volumes of transatction and
  high frequency tranding; government departments, the military and internal
  revenue who require huge databases.

raw_content:
  ---
  tags: [computer-history]
  created: Friday, September 27, 2024
  ---

  # Mainframe computers

  A mainframe computer, also known as a "big iron" is a high performance computer
  used for resource-intensive tasks that require greater security and availability
  than smaller scale machines. They are typically used for centralised rather than
  distributed computing.

  The heyday of mainframes was before the mini- and micro-computer revolution but
  they are still used.

  IBM remains the main manufacturer and service provider for mainframes. Example
  use cases include banks who need to process large volumes of transatction and
  high frequency tranding; government departments, the military and internal
  revenue who require huge databases.


path: Managing_environments_in_NodeJS.md
sortable_path: Managing_environments_in_NodeJS.md
title: Managing environments
lead: With a full-scale Node application you will typically run three environments:
checksum: 036a86541e04215403232e121dc96a105197f73db8d435c9bf4d6f02d68aa280
created: 2024-10-22 16:52:57.648648572+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["node-js"]}
body:
  With a full-scale Node application you will typically run three environments:

  - Development
  - Testing
  - Production

  ## Accessing the current environment

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

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

  ### Setting the Node environment

  #### For the session

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

  ```bash
  export NODE_ENV=production
  ```

  ### In Express

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

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

  ## Configuring environments

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

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

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

  For example:

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

  Then to utilise config variables:

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

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

  ### Sensitive config data

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

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

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

  Let's create an environmental variable for a password:

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

  Then in our custom variable file:

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

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

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

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

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

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

  # Managing environments

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

  - Development
  - Testing
  - Production

  ## Accessing the current environment

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

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

  ### Setting the Node environment

  #### For the session

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

  ```bash
  export NODE_ENV=production
  ```

  ### In Express

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

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

  ## Configuring environments

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

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

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

  For example:

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

  Then to utilise config variables:

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

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

  ### Sensitive config data

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

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

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

  Let's create an environmental variable for a password:

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

  Then in our custom variable file:

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

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

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

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

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


path: Map_and_filter_in_Python.md
sortable_path: Map_and_filter_in_Python.md
title: Map and filter in Python
lead: ## Map
checksum: 657b2624c0782eaa5f2b92a064f41d79185fc42eef1be5b4c8ab202f87745c76
created: 2024-10-22 16:52:57.667774248+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["python"]}
body:
  ## Map

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]

  new_data = map(lambda i: i + 10, data)
  print(new_data)
  ```

  We can also pass-in a function rather than use a lambda:

  ```py
  def add_one(i):
      return i + 1

  x = list(map(addOne, data))
  # [2, 4, 6, 3, 8, 5, 11]
  # necessary to add `list` to get some output
  ```

  ### Map returns an object

  When you run `map` against a list it returns a map object not a list. This can
  present problems if you are not aware of it since it is not an entity that you
  can loop through.

  The following map removes whitespaces from elements in a list:

  ```py
    lines = map(lambda x: x.strip(), lines)
  ```

  In order to be able to run list-like operations against the resulting `lines`
  object we would need to convert it to a list:

  ```py
    lines = list(map(lambda x: x.strip(), lines))
  ```

  ## Filter

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]

  d1 = list(filter(lambda i: i % 2 == 0, data))
  print(d1)
  #  [2, 4, 10]

  def is_even(i):
      return i % 2 == 0


  # Filter for even numbers using a named function
  d2 = list(filter(is_even, data))

  # [2, 4, 10]
  ```

  ## Chaining

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]
  new_data = list(map(lambda i: i + 10, filter(is_even, data)))
  print(new_data)
  # new_data: [12, 14, 20]
  ```

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

  # Map and filter in Python

  ## Map

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]

  new_data = map(lambda i: i + 10, data)
  print(new_data)
  ```

  We can also pass-in a function rather than use a lambda:

  ```py
  def add_one(i):
      return i + 1

  x = list(map(addOne, data))
  # [2, 4, 6, 3, 8, 5, 11]
  # necessary to add `list` to get some output
  ```

  ### Map returns an object

  When you run `map` against a list it returns a map object not a list. This can
  present problems if you are not aware of it since it is not an entity that you
  can loop through.

  The following map removes whitespaces from elements in a list:

  ```py
    lines = map(lambda x: x.strip(), lines)
  ```

  In order to be able to run list-like operations against the resulting `lines`
  object we would need to convert it to a list:

  ```py
    lines = list(map(lambda x: x.strip(), lines))
  ```

  ## Filter

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]

  d1 = list(filter(lambda i: i % 2 == 0, data))
  print(d1)
  #  [2, 4, 10]

  def is_even(i):
      return i % 2 == 0


  # Filter for even numbers using a named function
  d2 = list(filter(is_even, data))

  # [2, 4, 10]
  ```

  ## Chaining

  ```py
  data = [1, 3, 5, 2, 7, 4, 10]
  new_data = list(map(lambda i: i + 10, filter(is_even, data)))
  print(new_data)
  # new_data: [12, 14, 20]
  ```


path: Map_and_filter_to_reduce_in_JS.md
sortable_path: Map_and_filter_to_reduce_in_JS.md
title: Expressing combined map and filter operations to a single reduce
lead: ## `map` + `filter`
checksum: c55ae1785e85ae7113094c8c7f48a7190f3e0eb2cec9022f07c79701ce3fea0a
created: 2024-10-22 16:52:57.671639363+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["javascript"]}
body:
  ## `map` + `filter`

  The following combines a `map` and a `filter` to square a list of numbers and
  then filter the ones that are greater than or equal to 10:

  ```js
  const arr = [1, 2, 3, 4];

  const filteredSquaredNumbers = arr.map((x) => x * x).filter((y) => y >= 10);
  ```

  Using `reduce` we can combine these operations more concisely:

  ```js
  const filteredSquaredNumbers = arr.reduce((acc, x) => {
    const squared = x * x;
    if (squared >= 10) {
      acc.push(squared);
    }
    return acc;
  }, []);
  ```

  ## `filter` + `map`

  Here we use a filter and then a map to filter the even numbers and then double
  them:

  ```js
  const arr = [1, 2, 3, 4];

  const evenDoubled = arr.filter((x) => x % 2 === 0).map((y) => y * 2);
  ```

  Using `reduce` :

  ```js
  const evenDoubled = arr.reduce((acc, x) => {
    if (x % 2 === 0) {
      acc.push(x * 2);
    }
    return acc;
  }, []);
  ```

  > The empty array [] is the initial value of the accumulator. As the callback
  > function processes each element of the array, it can add or modify the
  > accumulator based on the desired logic. By providing an empty array as the
  > initial value for the accumulator, we ensure that the results will be
  > collected in a new array without modifying the original array.

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

  # Expressing combined map and filter operations to a single reduce

  ## `map` + `filter`

  The following combines a `map` and a `filter` to square a list of numbers and
  then filter the ones that are greater than or equal to 10:

  ```js
  const arr = [1, 2, 3, 4];

  const filteredSquaredNumbers = arr.map((x) => x * x).filter((y) => y >= 10);
  ```

  Using `reduce` we can combine these operations more concisely:

  ```js
  const filteredSquaredNumbers = arr.reduce((acc, x) => {
    const squared = x * x;
    if (squared >= 10) {
      acc.push(squared);
    }
    return acc;
  }, []);
  ```

  ## `filter` + `map`

  Here we use a filter and then a map to filter the even numbers and then double
  them:

  ```js
  const arr = [1, 2, 3, 4];

  const evenDoubled = arr.filter((x) => x % 2 === 0).map((y) => y * 2);
  ```

  Using `reduce` :

  ```js
  const evenDoubled = arr.reduce((acc, x) => {
    if (x % 2 === 0) {
      acc.push(x * 2);
    }
    return acc;
  }, []);
  ```

  > The empty array [] is the initial value of the accumulator. As the callback
  > function processes each element of the array, it can add or modify the
  > accumulator based on the desired logic. By providing an empty array as the
  > initial value for the accumulator, we ensure that the results will be
  > collected in a new array without modifying the original array.


path: Mapped_types_in_TS.md
sortable_path: Mapped_types_in_TS.md
title: Mapped types in TypeScript
lead:
  A mapped type is a way to create new types based on existing ones by
  transforming their properties

checksum: ccabedb3387b7583fb0265e8e625b02b3cfe9ddc04875240fe8f29b61a4fab8e
created: 2024-10-22 16:52:57.675141816+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["typescript"]}
body:
  A mapped type is a way to create new types based on existing ones by
  transforming their properties

  As it works on a single type and typically narrows or limits the properties it
  works in a way that is opposite to a [union]() or [intersection]() type.

  > Mapped types are an example of when `type` is preferable to `interface`, since
  > you cannot generate mapped types as interfaces, although you may generate a
  > mapped type from an interface.

  For the demonstrations we will use the following type as the example that we
  will map from:

  ```ts
  type Person = {
    name: string;
    age: number;
    city: string;
    country: string;
  };
  ```

  ## Main varieties of mapped types

  ### Read only

  Creates a type with all properties of the given type set to `readonly`:

  ```ts
  type Readonly<T> = {
    readonly [P in keyof T]: T[P];
  };

  type ReadonlyPerson = Readonly<Person>;
  ```

  This is equivalent to:

  ```ts
  type ReadonlyPerson = {
    readonly name: string;
    readonly age: number;
    readonly city: string;
    readonly country: string;
  };
  ```

  ### Partial

  Creates a type with all properties of the given type set to optional.

  ```ts
  type Partial<T> = {
    [P in keyof T]?: T[P];
  };

  type PartialPerson = Partial<Person>;
  ```

  This is equivalent to:

  ```ts
  type PartialPerson = {
    name?: string;
    age?: number;
    city?: string;
    country?: string;
  };
  ```

  ### Pick

  This is useful when you want to create a new type based on a subset of
  properties from an existing type.

  ```ts
  type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
  };

  type PersonNameAndAge = Pick<Person, "name" | "age">;
  ```

  This is equivalent to:

  ```ts
  type PersonNameAndAge = {
    name: string;
    age: number;
  };
  ```

  ### Record

  Creates a type with keys of the given type and values of the specified type. It
  is a way of shoehorning keys from an existing type with new values.

  Basic syntax:

  ```ts
  Record<Keys, ValueType>;
  ```

  Example:

  ```ts
  type UserRole = "admin" | "user" | "guest";

  // Create a Record type to store user role descriptions
  type UserRoleDescriptions = Record<UserRole, string>;

  // Create an object that implements the UserRoleDescriptions type
  const roleDescriptions: UserRoleDescriptions = {
    admin: "Has full access to the system",
    user: "Can access limited resources",
    guest: "Can view public resources only",
  };
  ```

  Here is a simpler example

  ```ts
  type Person = {
    name: string;
    nationality: string;
  };

  type PersonInstance = Record<string, Person>;
  const thomasInstance: PersonInstance = {
    thomas: {
      name: "Thomas",
      nationality: "British",
    },
  };
  ```

  ### Exclude

  Creates a type by excluding specific properties from the given type.

  ```ts
  type Exclude<T, U> = T extends U ? never : T;

  type KeysWithoutAge = Exclude<keyof Person, "age">;
  ```

  This is equivalent to:

  ```ts
  type KeysWithoutAge = "name" | "city" | "country";
  ```

  ### Extract

  Creates a type by extracting specific properties from the given type. Basically
  the opposite operation to Exclude.

  ```ts
  type Extract<T, U> = T extends U ? T : never;

  type NameKey = Extract<keyof Person, "name">;
  ```

  This is equivalent to:

  ```ts
  type NameKey = "name";
  ```

  ### Non-nullable

  Creates a type by removing null and undefined from the given type.

  ```ts
  type NonNullable<T> = T extends null | undefined ? never : T;

  type NullablePerson = {
    name: string | null;
    age: number | null;
    city: string | null;
    country: string | null;
  };

  type NonNullablePerson = NonNullable<NullablePerson>;
  ```

  Equivalent to:

  ```ts
  type NonNullablePerson = {
    name: string;
    age: number;
    city: string;
    country: string;
  };
  ```

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

  # Mapped types in TypeScript

  A mapped type is a way to create new types based on existing ones by
  transforming their properties

  As it works on a single type and typically narrows or limits the properties it
  works in a way that is opposite to a [union]() or [intersection]() type.

  > Mapped types are an example of when `type` is preferable to `interface`, since
  > you cannot generate mapped types as interfaces, although you may generate a
  > mapped type from an interface.

  For the demonstrations we will use the following type as the example that we
  will map from:

  ```ts
  type Person = {
    name: string;
    age: number;
    city: string;
    country: string;
  };
  ```

  ## Main varieties of mapped types

  ### Read only

  Creates a type with all properties of the given type set to `readonly`:

  ```ts
  type Readonly<T> = {
    readonly [P in keyof T]: T[P];
  };

  type ReadonlyPerson = Readonly<Person>;
  ```

  This is equivalent to:

  ```ts
  type ReadonlyPerson = {
    readonly name: string;
    readonly age: number;
    readonly city: string;
    readonly country: string;
  };
  ```

  ### Partial

  Creates a type with all properties of the given type set to optional.

  ```ts
  type Partial<T> = {
    [P in keyof T]?: T[P];
  };

  type PartialPerson = Partial<Person>;
  ```

  This is equivalent to:

  ```ts
  type PartialPerson = {
    name?: string;
    age?: number;
    city?: string;
    country?: string;
  };
  ```

  ### Pick

  This is useful when you want to create a new type based on a subset of
  properties from an existing type.

  ```ts
  type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
  };

  type PersonNameAndAge = Pick<Person, "name" | "age">;
  ```

  This is equivalent to:

  ```ts
  type PersonNameAndAge = {
    name: string;
    age: number;
  };
  ```

  ### Record

  Creates a type with keys of the given type and values of the specified type. It
  is a way of shoehorning keys from an existing type with new values.

  Basic syntax:

  ```ts
  Record<Keys, ValueType>;
  ```

  Example:

  ```ts
  type UserRole = "admin" | "user" | "guest";

  // Create a Record type to store user role descriptions
  type UserRoleDescriptions = Record<UserRole, string>;

  // Create an object that implements the UserRoleDescriptions type
  const roleDescriptions: UserRoleDescriptions = {
    admin: "Has full access to the system",
    user: "Can access limited resources",
    guest: "Can view public resources only",
  };
  ```

  Here is a simpler example

  ```ts
  type Person = {
    name: string;
    nationality: string;
  };

  type PersonInstance = Record<string, Person>;
  const thomasInstance: PersonInstance = {
    thomas: {
      name: "Thomas",
      nationality: "British",
    },
  };
  ```

  ### Exclude

  Creates a type by excluding specific properties from the given type.

  ```ts
  type Exclude<T, U> = T extends U ? never : T;

  type KeysWithoutAge = Exclude<keyof Person, "age">;
  ```

  This is equivalent to:

  ```ts
  type KeysWithoutAge = "name" | "city" | "country";
  ```

  ### Extract

  Creates a type by extracting specific properties from the given type. Basically
  the opposite operation to Exclude.

  ```ts
  type Extract<T, U> = T extends U ? T : never;

  type NameKey = Extract<keyof Person, "name">;
  ```

  This is equivalent to:

  ```ts
  type NameKey = "name";
  ```

  ### Non-nullable

  Creates a type by removing null and undefined from the given type.

  ```ts
  type NonNullable<T> = T extends null | undefined ? never : T;

  type NullablePerson = {
    name: string | null;
    age: number | null;
    city: string | null;
    country: string | null;
  };

  type NonNullablePerson = NonNullable<NullablePerson>;
  ```

  Equivalent to:

  ```ts
  type NonNullablePerson = {
    name: string;
    age: number;
    city: string;
    country: string;
  };
  ```


path: Maps_and_sets_in_JS.md
sortable_path: Maps_and_sets_in_JS.md
title: Maps and Sets
checksum: 391de8d7c7b97236ff25a0ce78fc54bd629b9d1010dd5c1ed91b6de808339bac
created: 2024-10-22 16:52:57.679368973+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["javascript"]}
lead:
  > Both `Map` and `Set` are new data structures introduced with ES6. They combine
  > the properties of the pre-existing data structures: arrays and objects and
  > offer advantages in certain non-typical use cases.

body:
  > Both `Map` and `Set` are new data structures introduced with ES6. They combine
  > the properties of the pre-existing data structures: arrays and objects and
  > offer advantages in certain non-typical use cases.

  ## Maps

  ### Concepts

  A map (not to be confused with the array map method) introduces something like
  the associative array model to JavaScript. Prior to ES6 the closest thing JS had
  to this was an object.

  Maps are like objects in that their structure consists in key/map pairs but like
  arrays in that the order in which the entries are placed is retained and can be
  referred to throughout the lifecycle of the Map. Also, the length of the Map is
  a known and easily returnable quantity, with objects we have to do some
  wrangling with `Object.keys` and `Object.entries` to retrieve meta data about
  the object itself. Moreover, with an object the order in which the keys are
  stored is not recorded.

  At the same time Maps are different from arrays because the index of an array
  element is not unique, it will always be a number of the form `[0], [1], [2]...`
  .

  Finally, the key can be any data type not just a string. This is an important
  characteristic of maps because although you can use numbers or booleans as the
  keys in an object, they are not actually numbers, they are converted to strings
  at execution. With Maps, whatever data type you assign as a key, retains its
  type.

  Maps

  - Have key/value pair structure
  - Have length property
  - Order of entries and insertions is maintained
  - Can use any data type as a key
  - Disallow duplicate keys

  ### Creating a Map and adding entries

  ```jsx
  const map = new Map();

  // We then pass in key/value pairs using `set`:
  map.set("firstName", "Luke");
  map.set("lastName", "Skywalker");
  map.set("occupation", "Jedi Knight");
  ```

  There is an alternative method for defining a map:

  ```jsx
  const map = new Map([
    ["firstName", "Luke"],
    ["lastName", "Skywalker"],
    ["occupation", "Jedi Knight"],
  ]);
  ```

  Internally, this data will be represented as follows:

  ```
  Map(3)
  0: {"firstName" => "Luke"}
  1: {"lastName" => "Skywalker"}
  2: {"occupation" => "Jedi Knight"}
  ```

  ### Working with map elements

  ```jsx
  // check for the existence of an item in a map by searching for existence of key
  map.has("firstName"); // return boolean

  // return all keys in a Map as iterator
  map.keys(); // MapIterator {'firstName', 'lastName', 'occupation'}

  // return all values as iterator
  map.values();

  // return array of key/value pairs
  map.entries(); // {"firstName" => "Luke", "lastName" => "Skywalker", "occupation" => "Jedi Knight"}
  // retrieve an item from a Map
  map.get("lastName"); // Skywalker

  // delete an item from a map by key, returns boolean as confirmation
  map.delete("occupation"); // true

  //return the length of a map (just like array.length)
  map.size; // 3
  // clear all values
  map.clear();
  ```

  ### Looping

  ```jsx
  // Map has its own .forEach method, like with arrays. Hewre they are side by side

  // Map
  Map.prototype.forEach((value, key, map) = () => {})

  // Array
  Array.prototype.forEach((item, index, array) = () => {})

  // You can also use a for of loop
  // Destructure the key and value out of the Map item
  for (const [key, value] of map) {
    // Log the keys and values of the Map with for...of
    console.log(`${key}: ${value}`)
  }
  ```

  ### Interfacing between Maps and other reference types

  Given that we can create a map with both object and array-style syntax, its easy
  to convert maps to and from the more established data structures.

  It's easy to convert an object to a map:

  ```jsx
  const luke = {
    firstName: "Luke",
    lastName: "Skywalker",
    occupation: "Jedi Knight",
  };

  const map = new Map(Object.entries(luke));
  ```

  And a map to an object:

  ```jsx
  const obj = Object.fromEntries(map);
  ```

  A map to an array:

  ```jsx
  const arr = Array.from(map);
  ```

  We saw earlier that a Map is a multidimensional array, so any multidimensional
  array can be used in the Map constructor invocation to turn it into a Map.

  ## Sets

  A set is special kind of array, an atypical supplement to arrays. It is
  basically an array of unique values. If you try to add a duplicate entry to a
  set it will be ignored.

  ```jsx
  const set = new Set();
  set.add("Beethoven");
  set.add("Bach");

  // Or:
  const set = new Set(["Beethoven", "Bach"]);

  // Convert array to set (note, this will remove duplicates on initialisation)
  const arr = [...set];
  ```

  We can use `keys()`, `values()`, and `entries()` with sets but obviously, `keys`
  and `values` will be identical.

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

  # Maps and Sets

  > Both `Map` and `Set` are new data structures introduced with ES6. They combine
  > the properties of the pre-existing data structures: arrays and objects and
  > offer advantages in certain non-typical use cases.

  ## Maps

  ### Concepts

  A map (not to be confused with the array map method) introduces something like
  the associative array model to JavaScript. Prior to ES6 the closest thing JS had
  to this was an object.

  Maps are like objects in that their structure consists in key/map pairs but like
  arrays in that the order in which the entries are placed is retained and can be
  referred to throughout the lifecycle of the Map. Also, the length of the Map is
  a known and easily returnable quantity, with objects we have to do some
  wrangling with `Object.keys` and `Object.entries` to retrieve meta data about
  the object itself. Moreover, with an object the order in which the keys are
  stored is not recorded.

  At the same time Maps are different from arrays because the index of an array
  element is not unique, it will always be a number of the form `[0], [1], [2]...`
  .

  Finally, the key can be any data type not just a string. This is an important
  characteristic of maps because although you can use numbers or booleans as the
  keys in an object, they are not actually numbers, they are converted to strings
  at execution. With Maps, whatever data type you assign as a key, retains its
  type.

  Maps

  - Have key/value pair structure
  - Have length property
  - Order of entries and insertions is maintained
  - Can use any data type as a key
  - Disallow duplicate keys

  ### Creating a Map and adding entries

  ```jsx
  const map = new Map();

  // We then pass in key/value pairs using `set`:
  map.set("firstName", "Luke");
  map.set("lastName", "Skywalker");
  map.set("occupation", "Jedi Knight");
  ```

  There is an alternative method for defining a map:

  ```jsx
  const map = new Map([
    ["firstName", "Luke"],
    ["lastName", "Skywalker"],
    ["occupation", "Jedi Knight"],
  ]);
  ```

  Internally, this data will be represented as follows:

  ```
  Map(3)
  0: {"firstName" => "Luke"}
  1: {"lastName" => "Skywalker"}
  2: {"occupation" => "Jedi Knight"}
  ```

  ### Working with map elements

  ```jsx
  // check for the existence of an item in a map by searching for existence of key
  map.has("firstName"); // return boolean

  // return all keys in a Map as iterator
  map.keys(); // MapIterator {'firstName', 'lastName', 'occupation'}

  // return all values as iterator
  map.values();

  // return array of key/value pairs
  map.entries(); // {"firstName" => "Luke", "lastName" => "Skywalker", "occupation" => "Jedi Knight"}
  // retrieve an item from a Map
  map.get("lastName"); // Skywalker

  // delete an item from a map by key, returns boolean as confirmation
  map.delete("occupation"); // true

  //return the length of a map (just like array.length)
  map.size; // 3
  // clear all values
  map.clear();
  ```

  ### Looping

  ```jsx
  // Map has its own .forEach method, like with arrays. Hewre they are side by side

  // Map
  Map.prototype.forEach((value, key, map) = () => {})

  // Array
  Array.prototype.forEach((item, index, array) = () => {})

  // You can also use a for of loop
  // Destructure the key and value out of the Map item
  for (const [key, value] of map) {
    // Log the keys and values of the Map with for...of
    console.log(`${key}: ${value}`)
  }
  ```

  ### Interfacing between Maps and other reference types

  Given that we can create a map with both object and array-style syntax, its easy
  to convert maps to and from the more established data structures.

  It's easy to convert an object to a map:

  ```jsx
  const luke = {
    firstName: "Luke",
    lastName: "Skywalker",
    occupation: "Jedi Knight",
  };

  const map = new Map(Object.entries(luke));
  ```

  And a map to an object:

  ```jsx
  const obj = Object.fromEntries(map);
  ```

  A map to an array:

  ```jsx
  const arr = Array.from(map);
  ```

  We saw earlier that a Map is a multidimensional array, so any multidimensional
  array can be used in the Map constructor invocation to turn it into a Map.

  ## Sets

  A set is special kind of array, an atypical supplement to arrays. It is
  basically an array of unique values. If you try to add a duplicate entry to a
  set it will be ignored.

  ```jsx
  const set = new Set();
  set.add("Beethoven");
  set.add("Bach");

  // Or:
  const set = new Set(["Beethoven", "Bach"]);

  // Convert array to set (note, this will remove duplicates on initialisation)
  const arr = [...set];
  ```

  We can use `keys()`, `values()`, and `entries()` with sets but obviously, `keys`
  and `values` will be identical.


path: Match_statements_in_Python.md
sortable_path: Match_statements_in_Python.md
title: Match statements in Python
lead: > A `match` statement is the equivalent of a switch or case statement in Python
checksum: 4eca8abdc2e26149bf6e163394aa1e01aaef771d47d653884dac8ec213313c40
created: 2024-10-22 16:52:57.68401475+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["python"]}
body:
  > A `match` statement is the equivalent of a switch or case statement in Python

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

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

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

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

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

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

  # Match statements in Python

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

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

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

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

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

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


path: Matter_and_atoms.md
sortable_path: Matter_and_atoms.md
title: Matter and atoms
lead: ## Matter, elements, compounds and mixtures
checksum: 3f5628d93b77e4acadfd3a283c09d933482db0d3e12f6dda0d3487836d3b4174
created: 2024-10-22 16:52:57.688145221+00:00
modified: 2024-10-18 17:55:56.289060649+00:00
metadata: {"tags":["physics"]}
body:
  ## Matter, elements, compounds and mixtures

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

  ## Atoms and molecules

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

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



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

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

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

  ### Atomic number

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

  ### Atomic weight

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

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

  # Matter and atoms

  ## Matter, elements, compounds and mixtures

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

  ## Atoms and molecules

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

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



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

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

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

  ### Atomic number

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

  ### Atomic weight

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


path: Memoization_in_React.md
sortable_path: Memoization_in_React.md
title: Memoization with useCallback and useMemo
lead: ## Rationale
checksum: aa5a1396de6830c65cebe440419eb402597ac57d198d06fa5c5fe6cea81ab4f9
created: 2024-10-22 16:52:57.693210322+00:00
modified: 2024-10-18 17:55:56.295727437+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: Memory_Management_Unit.md
sortable_path: Memory_Management_Unit.md
title: Memory Management Unit (MMU)
checksum: 872a7691c78622056fe66b79197c0f6f9df56d1dba50321e9f4a17e5c3b52da0
created: 2024-10-22 16:52:57.7054847+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Monday, July 08, 2024","tags":["memory","Linux"]}
lead:
  The MMU is the bridge between the physical memory devices of the machine and the
  virtual memory space. It is a chip that sits between the CPU and the RAM and
  determines the physical location of the memory requested by the kernel as
  virtual memory.

body:
  The MMU is the bridge between the physical memory devices of the machine and the
  virtual memory space. It is a chip that sits between the CPU and the RAM and
  determines the physical location of the memory requested by the kernel as
  virtual memory.

  ![Virtual memory diagram](/img/virtual-memory-diagram.jpg)

  ## Pages

  We use the term **pages** to denote blocks of virtual memory and to distinguish
  them from **addresses** as physical blocks. The MMU possesses a **page table**
  which is registry logging which pages correspond to which physical blocks.

  ## Shared pages

  Virtual memory allows the sharing of files and memory by multiple processes.
  Crucially the shared data doesn't have to be within the address of each process,
  instead there is a reference in the page table that each process has access to
  the shared data.

  ## Page faults

  There are two kinds of error that can occur with relation to paged memory:

  - minor page faults
    - The desired page is in main memory but the MMU doesn't currently know where
      it is
  - major page faults
    - The desired page is not in main memory at all. Therefore the kernel must
      fetch it from disk

  Minor page faults are very common and are to be expected; they resolve quickly.
  On the other hand too many major page faults can slow the system down both
  because of the time-costly process of fetching data from disk and because it
  demands more kernel resources to locate the missing page, which puts other
  processes on hold.

raw_content:
  ---
  tags: [memory, Linux]
  created: Monday, July 08, 2024
  ---

  # Memory Management Unit (MMU)

  The MMU is the bridge between the physical memory devices of the machine and the
  virtual memory space. It is a chip that sits between the CPU and the RAM and
  determines the physical location of the memory requested by the kernel as
  virtual memory.

  ![Virtual memory diagram](/img/virtual-memory-diagram.jpg)

  ## Pages

  We use the term **pages** to denote blocks of virtual memory and to distinguish
  them from **addresses** as physical blocks. The MMU possesses a **page table**
  which is registry logging which pages correspond to which physical blocks.

  ## Shared pages

  Virtual memory allows the sharing of files and memory by multiple processes.
  Crucially the shared data doesn't have to be within the address of each process,
  instead there is a reference in the page table that each process has access to
  the shared data.

  ## Page faults

  There are two kinds of error that can occur with relation to paged memory:

  - minor page faults
    - The desired page is in main memory but the MMU doesn't currently know where
      it is
  - major page faults
    - The desired page is not in main memory at all. Therefore the kernel must
      fetch it from disk

  Minor page faults are very common and are to be expected; they resolve quickly.
  On the other hand too many major page faults can slow the system down both
  because of the time-costly process of fetching data from disk and because it
  demands more kernel resources to locate the missing page, which puts other
  processes on hold.


path: Memory_addresses.md
sortable_path: Memory_addresses.md
title: Memory addresses
checksum: cc19bb80c91935b16385412e0ca63bfa50e40344fd948e1b2782feeee141d9b2
created: 2024-10-22 16:52:57.709638041+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Friday, July 12, 2024","tags":["memory"]}
lead:
  > Computers assign numeric addresses to bytes of memory and the CPU can read or
  > write to those addresses

body:
  > Computers assign numeric addresses to bytes of memory and the CPU can read or
  > write to those addresses

  We can think of the internals of RAM as grids of memory cells.

  Each single-bit cell in the grid can be identified using two dimensional
  coordinates, like in a graph. The coordinates are the location of that cell in
  the grid.

  Handling one bit at a time isn't very efficient so RAM accesses **multiple
  grids** of 1-bit memory cells in parallel. This allows for reads or writes of
  multiple bits at once, such as a whole byte.

  The location of a set of bits in memory is known as a **memory address**.

  ### Demonstration

  Let's imagine we have a computer system that can address up to 64KB of memory
  and our system is byte addressable. This means there are
  $64 \cdot 1024 = 65,536$ bytes of memory because 1KB = 1024 bytes.

  We therefore have 65,536 addresses and each address can store one byte. So our
  addresses go from 0 to 65, 535.

  We now need to consider how many bits we need to uniquely represent an address
  on this system.

  What does this mean? Although there are approximately 64 thousand bytes of
  memory, to refer to each byte we can't just use 1, 2, 3... because computers use
  binary numbers. We need a binary number to refer to a given byte in the the 64KB
  of memory. The question we are asking is: how long does this binary number need
  to be to be able to represent each of the 64 thousand bytes?

  1 bit can represent two addresses: 0 and 1. 2 bits can represent four addresses:
  00, 01, 10, 11. The formula is as follows: number of addresses = $2^n$ where $n$
  is the number of bits.

  We need to reverse this formula to find out how many bits we need to represent a
  given number of addresses. We can do this with a [logarithm](Logarithms.md).

  We can reverse the formula as follows: number of bits = $\log_2$ (number of
  addresses).

  In our case we have 65,536 addresses so we need $\log_2(65,536)$ bits to
  represent each address. This is approximately 16 bits. Thus a 16 bit memory
  iaddress is needed to address 65, 546 bytes.

  Using memory addresses we end up with tables like the following:

  | Memory address   | Data             |
  | ---------------- | ---------------- |
  | 0000000000000000 | 1010101010101010 |
  | 0000000000000001 | 0010001001001011 |
  | 0000000000000010 | 0010001001001010 |

  This is hard to parse so we can instead use
  [hexadecimal numbers](Hexadecimal_number_system.md) to represent the addresses:

  | Memory address (as hex) | Data (as binary) |
  | ----------------------- | ---------------- |
  | 0x0000                  | 1010101010101010 |
  | 0x0001                  | 0010001001001011 |
  | 0x0002                  | 0010001001001010 |

  By itself, the the data is meaningless but we know from
  [binary encoding](Binary_encoding.md) that the binary data will correspond to
  some meaningful data, such as a character or a colour, depending on the encoding
  scheme used. The above table could correspond to the characters for 'A', 'B' and
  'C' in the ASCII encoding scheme:

  | Memory address (as hex) | Data (as binary) | Data (as ASCII) |
  | ----------------------- | ---------------- | --------------- |
  | 0x0000                  | 1010101010101010 | A               |
  | 0x0001                  | 0010001001001011 | B               |
  | 0x0002                  | 0010001001001010 | C               |

raw_content:
  ---
  tags: [memory]
  created: Friday, July 12, 2024
  ---

  # Memory addresses

  > Computers assign numeric addresses to bytes of memory and the CPU can read or
  > write to those addresses

  We can think of the internals of RAM as grids of memory cells.

  Each single-bit cell in the grid can be identified using two dimensional
  coordinates, like in a graph. The coordinates are the location of that cell in
  the grid.

  Handling one bit at a time isn't very efficient so RAM accesses **multiple
  grids** of 1-bit memory cells in parallel. This allows for reads or writes of
  multiple bits at once, such as a whole byte.

  The location of a set of bits in memory is known as a **memory address**.

  ### Demonstration

  Let's imagine we have a computer system that can address up to 64KB of memory
  and our system is byte addressable. This means there are
  $64 \cdot 1024 = 65,536$ bytes of memory because 1KB = 1024 bytes.

  We therefore have 65,536 addresses and each address can store one byte. So our
  addresses go from 0 to 65, 535.

  We now need to consider how many bits we need to uniquely represent an address
  on this system.

  What does this mean? Although there are approximately 64 thousand bytes of
  memory, to refer to each byte we can't just use 1, 2, 3... because computers use
  binary numbers. We need a binary number to refer to a given byte in the the 64KB
  of memory. The question we are asking is: how long does this binary number need
  to be to be able to represent each of the 64 thousand bytes?

  1 bit can represent two addresses: 0 and 1. 2 bits can represent four addresses:
  00, 01, 10, 11. The formula is as follows: number of addresses = $2^n$ where $n$
  is the number of bits.

  We need to reverse this formula to find out how many bits we need to represent a
  given number of addresses. We can do this with a [logarithm](Logarithms.md).

  We can reverse the formula as follows: number of bits = $\log_2$ (number of
  addresses).

  In our case we have 65,536 addresses so we need $\log_2(65,536)$ bits to
  represent each address. This is approximately 16 bits. Thus a 16 bit memory
  iaddress is needed to address 65, 546 bytes.

  Using memory addresses we end up with tables like the following:

  | Memory address   | Data             |
  | ---------------- | ---------------- |
  | 0000000000000000 | 1010101010101010 |
  | 0000000000000001 | 0010001001001011 |
  | 0000000000000010 | 0010001001001010 |

  This is hard to parse so we can instead use
  [hexadecimal numbers](Hexadecimal_number_system.md) to represent the addresses:

  | Memory address (as hex) | Data (as binary) |
  | ----------------------- | ---------------- |
  | 0x0000                  | 1010101010101010 |
  | 0x0001                  | 0010001001001011 |
  | 0x0002                  | 0010001001001010 |

  By itself, the the data is meaningless but we know from
  [binary encoding](Binary_encoding.md) that the binary data will correspond to
  some meaningful data, such as a character or a colour, depending on the encoding
  scheme used. The above table could correspond to the characters for 'A', 'B' and
  'C' in the ASCII encoding scheme:

  | Memory address (as hex) | Data (as binary) | Data (as ASCII) |
  | ----------------------- | ---------------- | --------------- |
  | 0x0000                  | 1010101010101010 | A               |
  | 0x0001                  | 0010001001001011 | B               |
  | 0x0002                  | 0010001001001010 | C               |


path: Memory_leaks.md
sortable_path: Memory_leaks.md
title: Memory leaks
checksum: a4d5c6a8df018b82e31f5ba1746250ef20d36dca5a43b5a7d7e425cf5ab4db22
created: 2024-10-22 16:52:57.724233159+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["memory"]}
lead:
  A memory leak occurs when you program memory and forget to delete it once you
  are finished. The consequences of memory leak is that it reduces the performance
  of the computer by reducing the amount of available memory. Eventually, in the
  worst case, too much of the available memory may become allocated and all or
  part of the system or device stops working correctly, the application fails, or
  the system slows down vastly.

body:
  A memory leak occurs when you program memory and forget to delete it once you
  are finished. The consequences of memory leak is that it reduces the performance
  of the computer by reducing the amount of available memory. Eventually, in the
  worst case, too much of the available memory may become allocated and all or
  part of the system or device stops working correctly, the application fails, or
  the system slows down vastly.

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

  # Memory leaks

  A memory leak occurs when you program memory and forget to delete it once you
  are finished. The consequences of memory leak is that it reduces the performance
  of the computer by reducing the amount of available memory. Eventually, in the
  worst case, too much of the available memory may become allocated and all or
  part of the system or device stops working correctly, the application fails, or
  the system slows down vastly.


path: Memory_versus_processor.md
sortable_path: Memory_versus_processor.md
title: Memory versus processor
checksum: 6934369b9b4e8234521db8a1b40ca54359cf20097fb1930b87ed62bdf8ea3206
created: 2024-10-22 16:52:57.730154945+00:00
modified: 2024-10-18 18:17:01.726525085+00:00
metadata: {"created":"Thursday, August 01, 2024","tags":["question"]}
lead:
  > Would a more powerful processor with average or reduced memory capacity
  > perform better than, equal to, or less than a less powerful processor with
  > more memory, in principle?

body:
  > Would a more powerful processor with average or reduced memory capacity
  > perform better than, equal to, or less than a less powerful processor with
  > more memory, in principle?

raw_content:
  ---
  tags: ["question"]
  created: Thursday, August 01, 2024
  ---

  # Memory versus processor

  > Would a more powerful processor with average or reduced memory capacity
  > perform better than, equal to, or less than a less powerful processor with
  > more memory, in principle?


path: Messaging_services.md
sortable_path: Messaging_services.md
title: AWS Messaging services
lead: ## SQS
checksum: eb8a75e05ac26b869762b86506c063c553af24181b6b7f0d27f7d451127bc5b8
created: 2024-10-22 16:52:57.734310152+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["AWS"]}
body:
  ## SQS

  > SQS: Simple Queue Service

  SQS is a service that allows you to send, store and receive messages between
  apps and software components built in AWS, with automatic encryption. It helps
  with decoupling and scaling.

  As the name indicates, its operating mode is that of a
  [queue](Queue.md) data structure offering first-in, first-out
  and other queue implementations.

  An example application of this would be to set up an SQS queue that receives
  messages and triggers a lambda whenever a new message is added.

  ## SNS

  > SNS: Simple Notification Service

  Similar to SQS but the focus is on notifications rather than messages, i.e
  events that fire when something specific happens, not just a message-send event.
  It can be used for passing notifications between applications or to persons
  through SMS, text, push notifications and email.

  **SNS pushes messages out to subscribers while SQS stores the messages until
  someone reads them.**

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

  # AWS Messaging services

  ## SQS

  > SQS: Simple Queue Service

  SQS is a service that allows you to send, store and receive messages between
  apps and software components built in AWS, with automatic encryption. It helps
  with decoupling and scaling.

  As the name indicates, its operating mode is that of a
  [queue](Queue.md) data structure offering first-in, first-out
  and other queue implementations.

  An example application of this would be to set up an SQS queue that receives
  messages and triggers a lambda whenever a new message is added.

  ## SNS

  > SNS: Simple Notification Service

  Similar to SQS but the focus is on notifications rather than messages, i.e
  events that fire when something specific happens, not just a message-send event.
  It can be used for passing notifications between applications or to persons
  through SMS, text, push notifications and email.

  **SNS pushes messages out to subscribers while SQS stores the messages until
  someone reads them.**


path: Middleware_in_NodeJS.md
sortable_path: Middleware_in_NodeJS.md
title: Middleware
lead: ## What is middleware?
checksum: cc530669082b3716b21388f1c2ef4e95e3e1c2d678e96e586dec2cc8a3f66f4b
created: 2024-10-22 16:52:57.743159778+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["node-js","middleware"]}
body:
  ## What is middleware?

  - Anything that terminates the `req, res` cycle counts as middleware. It is
    basically anything that acts as an intermediary once the request is received
    but before the resource is sent. A good example would be the
    `app.use(express.json()` or `app.use(bodyParser.json)` functions we call in
    order to be able to parse JSON that is sent from the client.
  - You will most likely have multiple middleware functions running at once. We
    call this intermediary part of the cycle the **request processing pipeline**.
  - Generally all middleware will be added as a property on the Express `app`
    instance with the `app.use(...)` syntax.

  ## Creating custom middleware functions

  ### Basic schema

  ```js
  app.use((req, res, next) => {
    // do some middleware
    next();
  });
  ```

  ### `next`

  The `next` parameter is key, it allows Express to move onto the next middleware
  function once the custom middleware executes. Without it, the request processing
  pipeline will get blocked.

  Middleware functions are basically asynchronous requests and as such they use a
  similar syntax as Promises (e.g `then`) for sequencing processes.

  ### Example of sequence

  ```js
  app.use((req, res, next) => {
    console.log("Do process A...");
    next();
  });

  app.use((req, res, next) => {
    console.log("Do process B...");
    next();
  });
  ```

  > It makes more sense of course to define our middleware within a function and
  > then pass it as an argument to `app.use()`

  ## Including middleware based on environment

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

  - Development
  - Testing
  - Production

  We will not want to run certain types of middleware in all environments. For
  example, it would be costly to run logging in the app's production environment.
  It would make more sense to run this only in development.

  ### Accessing current Node environment

  We can control which middleware we run via the Node envrionment variables:
  `process.env` (see for instance [ports](Ports_in_NodeJS.md)).

  We could set
  [Morgan](Morgan.md) to run
  only in development with:

  ```js
  if (app.get("env") === "development") {
    app.use(morgan("common"));
    console.log("Morgan enabled");
  }
  ```

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

  # Middleware

  ## What is middleware?

  - Anything that terminates the `req, res` cycle counts as middleware. It is
    basically anything that acts as an intermediary once the request is received
    but before the resource is sent. A good example would be the
    `app.use(express.json()` or `app.use(bodyParser.json)` functions we call in
    order to be able to parse JSON that is sent from the client.
  - You will most likely have multiple middleware functions running at once. We
    call this intermediary part of the cycle the **request processing pipeline**.
  - Generally all middleware will be added as a property on the Express `app`
    instance with the `app.use(...)` syntax.

  ## Creating custom middleware functions

  ### Basic schema

  ```js
  app.use((req, res, next) => {
    // do some middleware
    next();
  });
  ```

  ### `next`

  The `next` parameter is key, it allows Express to move onto the next middleware
  function once the custom middleware executes. Without it, the request processing
  pipeline will get blocked.

  Middleware functions are basically asynchronous requests and as such they use a
  similar syntax as Promises (e.g `then`) for sequencing processes.

  ### Example of sequence

  ```js
  app.use((req, res, next) => {
    console.log("Do process A...");
    next();
  });

  app.use((req, res, next) => {
    console.log("Do process B...");
    next();
  });
  ```

  > It makes more sense of course to define our middleware within a function and
  > then pass it as an argument to `app.use()`

  ## Including middleware based on environment

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

  - Development
  - Testing
  - Production

  We will not want to run certain types of middleware in all environments. For
  example, it would be costly to run logging in the app's production environment.
  It would make more sense to run this only in development.

  ### Accessing current Node environment

  We can control which middleware we run via the Node envrionment variables:
  `process.env` (see for instance [ports](Ports_in_NodeJS.md)).

  We could set
  [Morgan](Morgan.md) to run
  only in development with:

  ```js
  if (app.get("env") === "development") {
    app.use(morgan("common"));
    console.log("Morgan enabled");
  }
  ```


path: Mixed_and_improper_fractions.md
sortable_path: Mixed_and_improper_fractions.md
title: Mixed and improper fractions
lead: ## Improper fractions
checksum: 591035861210f541355bffec2836d38c935d09f90152f5328479bf5fca7cd409
created: 2024-10-22 16:52:57.757695806+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["prealgebra","fractions"]}
body:
  ## Improper fractions

  - Proper fraction:
    - The numerator is smaller than the denominator
    - E.g. $\frac{2}{3}$, $-\frac{5}{10}$
  - Improper fraction
    - The numerator is greater than the denominator
    - E.g. $\frac{3}{2}$, $-\frac{5}{4}$

  ## Mixed fractions

  A mixed fraction is part whole number, part fraction. For example:
  $5 \frac{3}{4}$.

  It means, in effect: $5 + \frac{3}{4}$

  ## Converting mixed fractions into improper fractions

  Mixed fractions are hard to calculate with. We need some way to convert them to
  fractions. We can do this by converting them to improper fractions.

  With the example $4 \frac{7}{8}$, we know this means $4 + \frac{7}{8}$. We need
  to express the amount 4 in terms of eighths. It would be 4 lots of $\frac{8}{8}$
  given that 4 is a whole number not a fractional amount. Thus the process would
  be:

  $$
      \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{7}{8}
  $$

  But we know that when we
  [add fractions with a common denominator](Add_Subtract_Fractions.md#adding-subracting-fractions-with-common-denominators),
  we only add the numerators, not the denominators. Thus the calculation would
  actually be:

  $$
  \frac{8 + 8 + 8 + 8 + 7}{8} = \frac{39}{8}
  $$

  Addition helps to explain the concepts underlying the procedure but it is more
  efficient to use multiplication.

  The procedure is as follows:

  1. Multiply the whole number part by the denominator
  2. Add the numerator
  3. Place the result over the denominator

  Thus:

  $$
      4 \frac{7}{8} = \frac{(4 \cdot 8) + 7 }{8}
  $$

  ## Converting improper fractions into mixed fractions

  It is quite obvious how to reverse the process and turn an improper fraction
  into a mixed fraction.

  Take $\frac{27}{5}$. We work out how many times the numerator is divisible by
  the denominator and make that the whole number. The remainder is then left as
  the fractional part.

  $$
  \begin{split}
  \frac{27}{5} = 27 \div 5  \\
  = 5 r 2 \\
  = 5 \frac{2}{5}
  \end{split}
  $$

  ## Multiplying and dividing by mixed fractions

  Now that we know how to convert mixed fractions into improper fractions, it is
  straight forward to multiply and divide with them. We convert the mixed fraction
  into an improper fraction and then divide and multiply as we would with a proper
  fraction.

  ### Demonstration of multiplication

  Calculate $-2\frac{1}{12} \cdot 2 \frac{4}{5}$:

  1. First convert each mixed fraction into an improper fraction:
     $$
       \begin{split}
       -2\frac{1}{12} = -2 \cdot -12  \\
       = 24 + 1 \\
       = - \frac{25}{12}
       \end{split}
     $$

  $$
  \begin{split}
    2 \frac{4}{5} =2 \cdot 5 \\
    = 10 + 4 \\
    = \frac{14}{5}
  \end{split}
  $$

  2. Then carry out the multiplication
     [using factorization](Multiplying_fractions.md#prime-factorisation-in-place):

     $$
       \begin{split}
       - \frac{25}{12} \cdot \frac{14}{5} = \\
      - \frac{(5 \cdot 5) \cdot (7 \cdot 2)}{(3 \cdot 2 \cdot 2) \cdot (5)} = - \frac{5 \cdot 7 }{2 \cdot 3} \\
       \end{split}
     $$

  3. Then simplify:

     $$
       - \frac{35}{6}
     $$

  4. Finally, convert back into a mixed fraction:

  $$
    \begin{split}
    - \frac{35}{6} = -35 \div 6 \\
    -  5 r 5 = \\
    - 5 \frac{5}{6}
    \end{split}
  $$

  ## Demonstration of division

  Again we convert the mixed fraction into an improper fraction and then follow
  the requisite rule, in the case of division this is to
  [invert and multiply](Dividing_fractions.md#formal-specification-of-how-to-divide-fractions').

  Calculate $-4 \frac{4}{5} \div 5 \frac{3}{5}$.

  1. Convert to improper fraction:
     $$
        \begin{split}
          -4 \cdot 5 = \\
      -20
     \end{split}
     $$

  ## Adding and subtracting mixed fractions

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

  # Mixed and improper fractions

  ## Improper fractions

  - Proper fraction:
    - The numerator is smaller than the denominator
    - E.g. $\frac{2}{3}$, $-\frac{5}{10}$
  - Improper fraction
    - The numerator is greater than the denominator
    - E.g. $\frac{3}{2}$, $-\frac{5}{4}$

  ## Mixed fractions

  A mixed fraction is part whole number, part fraction. For example:
  $5 \frac{3}{4}$.

  It means, in effect: $5 + \frac{3}{4}$

  ## Converting mixed fractions into improper fractions

  Mixed fractions are hard to calculate with. We need some way to convert them to
  fractions. We can do this by converting them to improper fractions.

  With the example $4 \frac{7}{8}$, we know this means $4 + \frac{7}{8}$. We need
  to express the amount 4 in terms of eighths. It would be 4 lots of $\frac{8}{8}$
  given that 4 is a whole number not a fractional amount. Thus the process would
  be:

  $$
      \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{8}{8} + \frac{7}{8}
  $$

  But we know that when we
  [add fractions with a common denominator](Add_Subtract_Fractions.md#adding-subracting-fractions-with-common-denominators),
  we only add the numerators, not the denominators. Thus the calculation would
  actually be:

  $$
  \frac{8 + 8 + 8 + 8 + 7}{8} = \frac{39}{8}
  $$

  Addition helps to explain the concepts underlying the procedure but it is more
  efficient to use multiplication.

  The procedure is as follows:

  1. Multiply the whole number part by the denominator
  2. Add the numerator
  3. Place the result over the denominator

  Thus:

  $$
      4 \frac{7}{8} = \frac{(4 \cdot 8) + 7 }{8}
  $$

  ## Converting improper fractions into mixed fractions

  It is quite obvious how to reverse the process and turn an improper fraction
  into a mixed fraction.

  Take $\frac{27}{5}$. We work out how many times the numerator is divisible by
  the denominator and make that the whole number. The remainder is then left as
  the fractional part.

  $$
  \begin{split}
  \frac{27}{5} = 27 \div 5  \\
  = 5 r 2 \\
  = 5 \frac{2}{5}
  \end{split}
  $$

  ## Multiplying and dividing by mixed fractions

  Now that we know how to convert mixed fractions into improper fractions, it is
  straight forward to multiply and divide with them. We convert the mixed fraction
  into an improper fraction and then divide and multiply as we would with a proper
  fraction.

  ### Demonstration of multiplication

  Calculate $-2\frac{1}{12} \cdot 2 \frac{4}{5}$:

  1. First convert each mixed fraction into an improper fraction:
     $$
       \begin{split}
       -2\frac{1}{12} = -2 \cdot -12  \\
       = 24 + 1 \\
       = - \frac{25}{12}
       \end{split}
     $$

  $$
  \begin{split}
    2 \frac{4}{5} =2 \cdot 5 \\
    = 10 + 4 \\
    = \frac{14}{5}
  \end{split}
  $$

  2. Then carry out the multiplication
     [using factorization](Multiplying_fractions.md#prime-factorisation-in-place):

     $$
       \begin{split}
       - \frac{25}{12} \cdot \frac{14}{5} = \\
      - \frac{(5 \cdot 5) \cdot (7 \cdot 2)}{(3 \cdot 2 \cdot 2) \cdot (5)} = - \frac{5 \cdot 7 }{2 \cdot 3} \\
       \end{split}
     $$

  3. Then simplify:

     $$
       - \frac{35}{6}
     $$

  4. Finally, convert back into a mixed fraction:

  $$
    \begin{split}
    - \frac{35}{6} = -35 \div 6 \\
    -  5 r 5 = \\
    - 5 \frac{5}{6}
    \end{split}
  $$

  ## Demonstration of division

  Again we convert the mixed fraction into an improper fraction and then follow
  the requisite rule, in the case of division this is to
  [invert and multiply](Dividing_fractions.md#formal-specification-of-how-to-divide-fractions').

  Calculate $-4 \frac{4}{5} \div 5 \frac{3}{5}$.

  1. Convert to improper fraction:
     $$
        \begin{split}
          -4 \cdot 5 = \\
      -20
     \end{split}
     $$

  ## Adding and subtracting mixed fractions


path: Modelling_relationships_in_MongoDB.md
sortable_path: Modelling_relationships_in_MongoDB.md
title: Modelling relationships between data
checksum: c7525be2f33aacca299e720d1ac1ad731bffae9e7b52c6557609fb4a43532a0e
created: 2024-10-22 16:52:57.773192467+00:00
modified: 2024-10-18 17:55:56.295727437+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: Module_pattern.md
sortable_path: Module_pattern.md
title: Module pattern
lead: > Come back and compare this with learning from Node.js
checksum: d667727226143e5e85a1f24373d72e77864e183a5b286cf980447b711f112e10
created: 2024-10-22 16:52:57.781731977+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["OOP","design-patterns"]}
body:
  > Come back and compare this with learning from Node.js

  With the module design pattern we create encapsulation: the variables and
  functions (as methods) are kept private inside the module and cannot be
  overwritten. This design pattern is familiar from Node.js development: every
  package you import into your project and download from NPM is a module.

  Generally you will create the module as a class, import it and then instantiate
  a new instance. However for private development, you could just as well use an
  object and duplicate it with `Object.create`.

  ## Example

  Here is an example of a simple module that returns the age of a person.

  ```js
  export default class Age {
    constructor(name, birthYear) {
      this.name = name;
      this.birthYear = birthYear;
    }
    currentYear() {
      return new Date().getFullYear();
    }
    get age() {
      return this.currentYear() - this.birthYear;
    }
  }
  ```

  ```js
  const martha = new Age("Martha", 1997);
  console.log(martha.age); // 24
  ```

  ## Controlling access

  In the example above, `aValue` could be edited in instantiations of the class.
  Given that modules should not be overwrittable, you could make it a private
  property on the class. The benefit of getters and setters is that they dictate
  what can be modified and retrieved from the module. So if you use `get` and
  `set` you can prevent overwrites.

  ## Object modules

  If you want to use an object instead of a class, you have to take greater care
  to ensure that the objects are not overwritable. **Also you cannot use the `#`
  modifier to make properties private.**

  - Use getters and setters for updating and retrieving values
  - Use `Object.seal` to prevent changes to the parent object
  - Instead of using getters and setters, for individual properties you can set
    `writable` to be `false` for properties that you don't want changed

  There are examples of each in the following:

  ```jsx
  export const age = {
    name: "",
    birthYear: new Number(),
    currentYear() {
      return new Date().getFullYear();
    },
    get age() {
      return this.currentYear() - this.birthYear;
    },
  };

  Object.seal(age);
  Object.defineProperty(age, "aValue", {
    value: 6,
    writable: false,
  });
  ```

raw_content:
  ---
  tags:
    - OOP
    - design-patterns
  ---

  # Module pattern

  > Come back and compare this with learning from Node.js

  With the module design pattern we create encapsulation: the variables and
  functions (as methods) are kept private inside the module and cannot be
  overwritten. This design pattern is familiar from Node.js development: every
  package you import into your project and download from NPM is a module.

  Generally you will create the module as a class, import it and then instantiate
  a new instance. However for private development, you could just as well use an
  object and duplicate it with `Object.create`.

  ## Example

  Here is an example of a simple module that returns the age of a person.

  ```js
  export default class Age {
    constructor(name, birthYear) {
      this.name = name;
      this.birthYear = birthYear;
    }
    currentYear() {
      return new Date().getFullYear();
    }
    get age() {
      return this.currentYear() - this.birthYear;
    }
  }
  ```

  ```js
  const martha = new Age("Martha", 1997);
  console.log(martha.age); // 24
  ```

  ## Controlling access

  In the example above, `aValue` could be edited in instantiations of the class.
  Given that modules should not be overwrittable, you could make it a private
  property on the class. The benefit of getters and setters is that they dictate
  what can be modified and retrieved from the module. So if you use `get` and
  `set` you can prevent overwrites.

  ## Object modules

  If you want to use an object instead of a class, you have to take greater care
  to ensure that the objects are not overwritable. **Also you cannot use the `#`
  modifier to make properties private.**

  - Use getters and setters for updating and retrieving values
  - Use `Object.seal` to prevent changes to the parent object
  - Instead of using getters and setters, for individual properties you can set
    `writable` to be `false` for properties that you don't want changed

  There are examples of each in the following:

  ```jsx
  export const age = {
    name: "",
    birthYear: new Number(),
    currentYear() {
      return new Date().getFullYear();
    },
    get age() {
      return this.currentYear() - this.birthYear;
    },
  };

  Object.seal(age);
  Object.defineProperty(age, "aValue", {
    value: 6,
    writable: false,
  });
  ```


path: Module_wrapping_at_runtime.md
sortable_path: Module_wrapping_at_runtime.md
title: Module wrapping at runtime in NodeJS
lead: ## The Module Wrapper Function
checksum: 7431983c6dab5cff64cb61f6e8b54daea923583fdfd33d8bf9d63152cb2c576c
created: 2024-10-22 16:52:57.786074585+00:00
modified: 2024-10-18 18:17:23.056924071+00:00
metadata: {"tags":["node-js"]}
body:
  ## The Module Wrapper Function

  When Node runs each of our module files are wrapped within an
  immediately-invoked function expression that has the following parameters:

  ```js
  (function (exports, require, module, __filename, __dirname))

  ```

  This is called the **module wrapper function**

  Note that one of these parameters is the
  [module object](Modules_in_NodeJS.md#structure-of-a-module).

  Within any module we can access these parameters: you can think of them as
  metadata about the module itself. `__filename` and `__dirname` are particularly
  useful when writing to files and modifying directories.

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

  # Module wrapping at runtime in NodeJS

  ## The Module Wrapper Function

  When Node runs each of our module files are wrapped within an
  immediately-invoked function expression that has the following parameters:

  ```js
  (function (exports, require, module, __filename, __dirname))

  ```

  This is called the **module wrapper function**

  Note that one of these parameters is the
  [module object](Modules_in_NodeJS.md#structure-of-a-module).

  Within any module we can access these parameters: you can think of them as
  metadata about the module itself. `__filename` and `__dirname` are particularly
  useful when writing to files and modifying directories.


path: Modules_in_NodeJS.md
sortable_path: Modules_in_NodeJS.md
title: Modules
checksum: 9d03b5ccc104e11c3ef76f35571497cf375083499eb5f3b5f78548785b8d21f0
created: 2024-10-22 16:52:57.79614053+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["node-js"]}
lead:
  > Modules are partitioned files where we define our variables and functions.
  > Values defined in modules are scoped to that specific module, constituting a
  > unique name space. This avoids name clashes in large programs.

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

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

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

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

  ## Structure of a module

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

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

  This gives us:

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

  ## Exports

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

  ### Exporting a whole module

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

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

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

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

  ### Exporting sub-components from a module

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

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

  exports.aVar = 321.3;

  var nonExportedVar = true;
  ```

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

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

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

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

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

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

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

  The import is the same:

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

  ## Structuring modules

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

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

  _Export a composite single function_

  ```js

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

  _Export an object_

  ```js

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

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

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

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

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

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

  # Modules

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

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

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

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

  ## Structure of a module

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

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

  This gives us:

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

  ## Exports

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

  ### Exporting a whole module

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

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

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

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

  ### Exporting sub-components from a module

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

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

  exports.aVar = 321.3;

  var nonExportedVar = true;
  ```

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

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

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

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

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

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

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

  The import is the same:

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

  ## Structuring modules

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

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

  _Export a composite single function_

  ```js

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

  _Export an object_

  ```js

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

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

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

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

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


path: MongoDB_Introduction.md
sortable_path: MongoDB_Introduction.md
title: MongoDB: Introduction
checksum: 13cf7e8e089a48db143051dddb2c02e86449cf2858d7aa9e44ec492618a668f5
created: 2024-10-22 16:52:57.801178911+00:00
modified: 2024-10-18 17:55:56.299060832+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: Monitoring_processes_and_resources.md
sortable_path: Monitoring_processes_and_resources.md
title: Monitoring processes and resources
lead: ## General purpose diagnostic programs (memory, CPU, I/O)
checksum: aba8ca7ab10e1624e6a830b9a98e2479627e63943d7a9232d53c77d167fbfbe4
created: 2024-10-22 16:52:57.820662659+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["systems-programming","Linux","procedural"]}
body:
  ## General purpose diagnostic programs (memory, CPU, I/O)

  ### `top`/`htop`

  We can use [ps](Processes.md) to list the
  currently running processes but it does not provide much information about the
  resource metrics or how the process changes over time. We can use `top` to get
  more information.

  `top` provides an interactive interface for the information that `ps` displays.
  It updates in real time and shows the most active processes based on the CPU
  time that they are utilising. You can also order by memory usage.

  _Here I have pressed `u` to show only the processes associated with my user:_

  ![](/img/htop.png)

  ### Main commands

  | Command | Action                          |
  | ------- | ------------------------------- |
  | -u      | Show processes by selected user |
  | M       | Sort by memory usage            |
  | P       | Sort by cumulative CPU usage    |
  | ?       | View key and explanation        |

  ### Understanding the categories

  - `Main/IO`
    - The first covers all processes. The second focuses on input/output processes
      (i.e. reading and writing to disks and other devices)
  - `PRI`
    - This stands for _priority_. This metric reflects the kernel's current
      schedule priority for the process. The higher the value, it is less likely
      that the kernel will schedule the process if there are competing processes
      that require CPU time. The lower the value, the greater priority this
      process has over others.
  - `NI`
    - This stands for _nice value_. This metric exists in order to allow
      administrators to nudge or influence the priority of a given process. You
      cannot directly tell the kernel to _do x now instead of y_ but you can make
      what are effectively suggestions by manipulating the nice value.
    - The kernel adds the nice value to the current priority value for the given
      process to determine its next time slot. When you increase the nice value of
      process _P_ you are being "nicer" to the other processes by influencing the
      priority of _P_ downwards so that the other processes receive greater
      precedence from the kernel.
    - By default, the nice value will be 0. To reduce priority of PID 1234, you
      would use:
      ```bash
      $ renice 20 1234
      ```
  - `VIRT`
    - The total amount of
      [virtual memory](Virtual_memory_and_the_MMU_in_Linux.md) used by
      the process including: program code, data, shared libraries, pages that have
      been swapped, pages that have been mapped but not used.
  - `RES`
    - Stands for _resident size_
    - The non swapped _physical_ memory the process has used
  - `SHR`
    - The size of the process's
      [shared pages](Virtual_memory_and_the_MMU_in_Linux.md#shared-pages)
  - `S`
    - Status:
      - S for sleeping (idle)
      - R for running
      - D for disk sleep

  ### `vmstat`

  `vmstat` provides similar metrics to `htop` but tells you more about the memory
  state and the activities of the kernel in a single row.

  The default output is a single line with the averages since boot. You can add a
  delay parameter (in secs) which will then output at that interval, allowing you
  to see memory usage in realtime, e.g:

  ```
  $ vmstat 5
  procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
   r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
   2  0      0 4326768 334228 5050952    0    0     8    19   80   10  4  1 94  0  0
   0  0      0 4365520 334260 5054468    0    0     0   125 2140 3434  4  1 94  0  0
   1  0      0 4382400 334276 5068940    0    0     0    77 2102 3988  3  1 95  0  0
   1  0      0 4434000 334288 5052908    0    0     0    25 2859 4278  6  1 92  0  0
   0  0      0 4391576 334304 5086484    0    0     0   110 2899 6480  8  3 90  0  0

  ```

  - `procs`
    - The number of runnable processes (`r`) and the number of blocked (`b`)
      processes
  - `memory`
    - The core memory output distinguishing:
      - Total kbs swapped to disk
      - Total kbs free
      - Total kbs currently in
        [buffer](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
        and not written
      - Total amount of virtual memory in the
        [cache](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
  - `swap`
    - Distinguishes amount of memory
      [swapped](Swap_space.md) in (`si`) to memory and
      swapped out (`so`) to disk
  - `io`
    - Disk actions
    - Amount of data read from harddisk (`bi`)
    - Amount of data written to harddisk (`bo`)
  - `system`
    - The number of times the kernel switches to kernel code
  - `cpu`
    - Percentage of the different CPU behaviours:
      - Responding to user tasks (`us`)
      - Time that it is idle (`id`)

  ## Files being used by active processes: `lsof`

  `lsof` stands for _list open files_. It lists opened files and the processes
  using them. Without modifiers it outputs a huge amount of data. The best way to
  use it is to execute it against a specific PID. For example the below output
  gives me some useful info about which files VS Code is using:

  ![](/img/lsof.png)

  ## System calls: `strace`

  A system call is when a process requests a service from the
  [kernel](The_kernel.md), for instance an I/O operation to
  memory. We can trace these system calls with `strace`.

  ## CPU performance

  We can use the `uptime` program to assess overall CPU performance in the form of
  a load average.

  > Load average is the number of active processes currently ready to run. It is
  > an estimate of the number of processes that are capable of using the CPU at
  > any given time.

  `Uptime` gives you three load averages:

  ```bash
  $ uptime
  11:19:16 up 14 days,  3:53,  1 user,  load average: 0.84, 0.57, 0.50
  ```

  - The three numbers are load averages for the past 1 minute, 5 minutes and 15
    minutes respectively.

  - A load average close to 0 is usually a good sign because it means that your
    processor isn't being challenged and you are conserving power. Anything equal
    to or above 1 means that a single process is using the CPU nearly all the
    time. You can identify that process with `htop` and it will obviously be near
    to the top. (This is often caused by Chrome and Electron-based software.)

  ## Memory status

  We know that processes primarily interact with virtual memory in the form of
  pages which are then translated to physical blocks by the kernel via the
  [MMU](Virtual_memory_and_the_MMU_in_Linux.md). There are several tools
  which provide windows onto this process.

  ### System page size

  We can view the overall system page size which is a representation of the amount
  of virtual memory available:

  ```bash
  $ getconf PAGE_SIZE
  4096
  ```

  This will typically be the same for all Linux systems.

  ### `free` : available physical memory

  `free` displays the total amount of free and¬used physical and swap memory in
  the system, as well as the
  [buffers and caches](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
  used by the kernel.

  ```bash
  $ free
                total        used        free      shared  buff/cache   available
  Mem:        16099420     5931512     5039344     2046460     5128564     7781904
  Swap:        3145724           0     3145724
  ```

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

  # Monitoring processes and resources

  ## General purpose diagnostic programs (memory, CPU, I/O)

  ### `top`/`htop`

  We can use [ps](Processes.md) to list the
  currently running processes but it does not provide much information about the
  resource metrics or how the process changes over time. We can use `top` to get
  more information.

  `top` provides an interactive interface for the information that `ps` displays.
  It updates in real time and shows the most active processes based on the CPU
  time that they are utilising. You can also order by memory usage.

  _Here I have pressed `u` to show only the processes associated with my user:_

  ![](/img/htop.png)

  ### Main commands

  | Command | Action                          |
  | ------- | ------------------------------- |
  | -u      | Show processes by selected user |
  | M       | Sort by memory usage            |
  | P       | Sort by cumulative CPU usage    |
  | ?       | View key and explanation        |

  ### Understanding the categories

  - `Main/IO`
    - The first covers all processes. The second focuses on input/output processes
      (i.e. reading and writing to disks and other devices)
  - `PRI`
    - This stands for _priority_. This metric reflects the kernel's current
      schedule priority for the process. The higher the value, it is less likely
      that the kernel will schedule the process if there are competing processes
      that require CPU time. The lower the value, the greater priority this
      process has over others.
  - `NI`
    - This stands for _nice value_. This metric exists in order to allow
      administrators to nudge or influence the priority of a given process. You
      cannot directly tell the kernel to _do x now instead of y_ but you can make
      what are effectively suggestions by manipulating the nice value.
    - The kernel adds the nice value to the current priority value for the given
      process to determine its next time slot. When you increase the nice value of
      process _P_ you are being "nicer" to the other processes by influencing the
      priority of _P_ downwards so that the other processes receive greater
      precedence from the kernel.
    - By default, the nice value will be 0. To reduce priority of PID 1234, you
      would use:
      ```bash
      $ renice 20 1234
      ```
  - `VIRT`
    - The total amount of
      [virtual memory](Virtual_memory_and_the_MMU_in_Linux.md) used by
      the process including: program code, data, shared libraries, pages that have
      been swapped, pages that have been mapped but not used.
  - `RES`
    - Stands for _resident size_
    - The non swapped _physical_ memory the process has used
  - `SHR`
    - The size of the process's
      [shared pages](Virtual_memory_and_the_MMU_in_Linux.md#shared-pages)
  - `S`
    - Status:
      - S for sleeping (idle)
      - R for running
      - D for disk sleep

  ### `vmstat`

  `vmstat` provides similar metrics to `htop` but tells you more about the memory
  state and the activities of the kernel in a single row.

  The default output is a single line with the averages since boot. You can add a
  delay parameter (in secs) which will then output at that interval, allowing you
  to see memory usage in realtime, e.g:

  ```
  $ vmstat 5
  procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
   r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
   2  0      0 4326768 334228 5050952    0    0     8    19   80   10  4  1 94  0  0
   0  0      0 4365520 334260 5054468    0    0     0   125 2140 3434  4  1 94  0  0
   1  0      0 4382400 334276 5068940    0    0     0    77 2102 3988  3  1 95  0  0
   1  0      0 4434000 334288 5052908    0    0     0    25 2859 4278  6  1 92  0  0
   0  0      0 4391576 334304 5086484    0    0     0   110 2899 6480  8  3 90  0  0

  ```

  - `procs`
    - The number of runnable processes (`r`) and the number of blocked (`b`)
      processes
  - `memory`
    - The core memory output distinguishing:
      - Total kbs swapped to disk
      - Total kbs free
      - Total kbs currently in
        [buffer](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
        and not written
      - Total amount of virtual memory in the
        [cache](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
  - `swap`
    - Distinguishes amount of memory
      [swapped](Swap_space.md) in (`si`) to memory and
      swapped out (`so`) to disk
  - `io`
    - Disk actions
    - Amount of data read from harddisk (`bi`)
    - Amount of data written to harddisk (`bo`)
  - `system`
    - The number of times the kernel switches to kernel code
  - `cpu`
    - Percentage of the different CPU behaviours:
      - Responding to user tasks (`us`)
      - Time that it is idle (`id`)

  ## Files being used by active processes: `lsof`

  `lsof` stands for _list open files_. It lists opened files and the processes
  using them. Without modifiers it outputs a huge amount of data. The best way to
  use it is to execute it against a specific PID. For example the below output
  gives me some useful info about which files VS Code is using:

  ![](/img/lsof.png)

  ## System calls: `strace`

  A system call is when a process requests a service from the
  [kernel](The_kernel.md), for instance an I/O operation to
  memory. We can trace these system calls with `strace`.

  ## CPU performance

  We can use the `uptime` program to assess overall CPU performance in the form of
  a load average.

  > Load average is the number of active processes currently ready to run. It is
  > an estimate of the number of processes that are capable of using the CPU at
  > any given time.

  `Uptime` gives you three load averages:

  ```bash
  $ uptime
  11:19:16 up 14 days,  3:53,  1 user,  load average: 0.84, 0.57, 0.50
  ```

  - The three numbers are load averages for the past 1 minute, 5 minutes and 15
    minutes respectively.

  - A load average close to 0 is usually a good sign because it means that your
    processor isn't being challenged and you are conserving power. Anything equal
    to or above 1 means that a single process is using the CPU nearly all the
    time. You can identify that process with `htop` and it will obviously be near
    to the top. (This is often caused by Chrome and Electron-based software.)

  ## Memory status

  We know that processes primarily interact with virtual memory in the form of
  pages which are then translated to physical blocks by the kernel via the
  [MMU](Virtual_memory_and_the_MMU_in_Linux.md). There are several tools
  which provide windows onto this process.

  ### System page size

  We can view the overall system page size which is a representation of the amount
  of virtual memory available:

  ```bash
  $ getconf PAGE_SIZE
  4096
  ```

  This will typically be the same for all Linux systems.

  ### `free` : available physical memory

  `free` displays the total amount of free and¬used physical and swap memory in
  the system, as well as the
  [buffers and caches](Role_of_memory_in_computation.md#relation-between-cache-and-buffers)
  used by the kernel.

  ```bash
  $ free
                total        used        free      shared  buff/cache   available
  Mem:        16099420     5931512     5039344     2046460     5128564     7781904
  Swap:        3145724           0     3145724
  ```


path: Morgan.md
sortable_path: Morgan.md
title: Morgan
lead: Morgan is middleware that is used to log HTTP requests to the Express instance.
checksum: 26ede6ed4dc04da810194afc819dca34945f17243a0803689e91c1a03c4c2568
created: 2024-10-22 16:52:57.883696662+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["node-js","middleware"]}
body:
  Morgan is middleware that is used to log HTTP requests to the Express instance.

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

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

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

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

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

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

  # Morgan

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

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

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

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

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

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


path: Motherboard.md
sortable_path: Motherboard.md
title: Motherboard
lead: <img src="../img/motherboard-pi.jpg" width="400px"/>
checksum: 0b164f3be04afb2fabe087cf47088189f48663b1e63986bb463fa53d9e6680cf
created: 2024-10-22 16:52:57.89001829+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["hardware","computer-architecture"]}
body:
  <img src="../img/motherboard-pi.jpg" width="400px"/>

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

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

raw_content:
  ---
  tags:
    - hardware
    - computer-architecture
  ---

  # Motherboard

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

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

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


path: Multiple_pointers.md
sortable_path: Multiple_pointers.md
title: Multiple pointers
checksum: c247415db8592dc1c4b8fca26b76001b0c53636ef5d2ef739c91ce609c3f8618
created: 2024-10-22 16:52:57.907964328+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["design-patterns"]}
lead:
  The multiple pointers pattern can be useful for moving through an array and
  comparing elements against each other in a time-efficient manner and without
  costly multiple loops.

body:
  The multiple pointers pattern can be useful for moving through an array and
  comparing elements against each other in a time-efficient manner and without
  costly multiple loops.

  ## Example: moving pairs

  In this example we shuffle through an array creating a pair from each element
  encountered. Thus for an array such as `[4, 3, 2, 1, 3, 6, 7]` we would return
  `[ [ 4, 3 ], [ 3, 2 ], [ 2, 1 ], [ 1, 3 ], [ 3, 6 ], [ 6, 7 ] ]`.

  ```js
  function movingPairs(arr) {
    const store = [];
    let left = 0;
    let right = 1;
    for (left; left < arr.length - right; left++) {
      store.push([arr[left], arr[right + left]]);
    }
    return store;
  }
  ```

  ## Example: identify unique values

  An example application of the above pattern would be identifying the number of
  unique values in an array that contains duplicates. One way to do this in
  JavaScript would be to use a Set however this is a more generic approach that
  only requires a single loop:

  ```js
  function uniqueValues(arr) {
    if (!arr.length) {
      return 0;
    } else {
      let count = 1;
      let left = 0;
      let right = 1;
      for (right; right < arr.length; right++) {
        if (arr[left] !== arr[right]) {
          count++;
        }
        left++;
      }

      return count;
    }
  }
  ```

  This works by having two pointers at either end of the array; one moving from
  the right and one moving from the left. Whilst the right pointer is less than
  the array length, the left pointer is incremented as the right moves closer to
  it. At each incrementation, the values of pointers (used as indexes) are
  compared for uniqueness, and a count is kept.

  ## Example: identify duplicates

  This is very similar to the above but this time we are looking for duplicates
  rather than unique values.

  ```js
  function areThereDuplicatesPointer(...input) {
    let start = 0;
    let next = 1;
    while (next < input.length) {
      let same = input[start] === input[next];
      if (same) {
        return true;
      }
      start++;
      next++;
    }

    return false;
  }
  console.log(areThereDuplicatesPointer(1, 2, 3)); // false
  console.log(areThereDuplicatesPointer(1, 2, 2)); // true
  ```

raw_content:
  ---
  tags:
    - design-patterns
  ---

  # Multiple pointers

  The multiple pointers pattern can be useful for moving through an array and
  comparing elements against each other in a time-efficient manner and without
  costly multiple loops.

  ## Example: moving pairs

  In this example we shuffle through an array creating a pair from each element
  encountered. Thus for an array such as `[4, 3, 2, 1, 3, 6, 7]` we would return
  `[ [ 4, 3 ], [ 3, 2 ], [ 2, 1 ], [ 1, 3 ], [ 3, 6 ], [ 6, 7 ] ]`.

  ```js
  function movingPairs(arr) {
    const store = [];
    let left = 0;
    let right = 1;
    for (left; left < arr.length - right; left++) {
      store.push([arr[left], arr[right + left]]);
    }
    return store;
  }
  ```

  ## Example: identify unique values

  An example application of the above pattern would be identifying the number of
  unique values in an array that contains duplicates. One way to do this in
  JavaScript would be to use a Set however this is a more generic approach that
  only requires a single loop:

  ```js
  function uniqueValues(arr) {
    if (!arr.length) {
      return 0;
    } else {
      let count = 1;
      let left = 0;
      let right = 1;
      for (right; right < arr.length; right++) {
        if (arr[left] !== arr[right]) {
          count++;
        }
        left++;
      }

      return count;
    }
  }
  ```

  This works by having two pointers at either end of the array; one moving from
  the right and one moving from the left. Whilst the right pointer is less than
  the array length, the left pointer is incremented as the right moves closer to
  it. At each incrementation, the values of pointers (used as indexes) are
  compared for uniqueness, and a count is kept.

  ## Example: identify duplicates

  This is very similar to the above but this time we are looking for duplicates
  rather than unique values.

  ```js
  function areThereDuplicatesPointer(...input) {
    let start = 0;
    let next = 1;
    while (next < input.length) {
      let same = input[start] === input[next];
      if (same) {
        return true;
      }
      start++;
      next++;
    }

    return false;
  }
  console.log(areThereDuplicatesPointer(1, 2, 3)); // false
  console.log(areThereDuplicatesPointer(1, 2, 2)); // true
  ```


path: Multiplexers_and_demultiplexers.md
sortable_path: Multiplexers_and_demultiplexers.md
title: Multiplexers (MUX) and demultiplexers (DMUX)
lead: ## Multiplexer
checksum: 0323d69672331653828e0e1eb7e963a330e2e4b67995bc169955b8bc65148eb7
created: 2024-10-22 16:52:57.912908063+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["logic-gates","binary","nand-to-tetris"]}
body:
  ## Multiplexer

  > Multiplexing is the generic term used to describe the operation of sending one
  > or more analogue or digital signals over a common transmission line at
  > different times or speeds.

  A multiplexer selects one of several input signals and forwards ths selected
  input to a single output line.

  We have two inputs (A,B) plus a third input SEL (for "select"). Applying a value
  to SEL toggles the output between A and B.

  ![](/img/MUX.png)

  Multiplexers can be used to build larger circuits by connecting the output of
  one multiplexer to the input of another. They are often used to implement data
  selection and switching in digital systems

  ### Programable gates

  One of the main use cases of multiplexers is to implement programmable gates.
  These are gates where the logic can be switched. For example an ANDMUXOR gate
  uses the SEL value to toggle the operation of a gate between AND and OR for its
  two inputs A and B

  ## Demultiplexer

  As the name suggests, a demultiplexer reverses the functionality of a
  multiplexer. It receives a single input and based on the selection of the SEL
  input it channels it to either an A or a B output.

  ![](/img/DMUX.png)

  We can think of it as a distributor of a value into one of several possible
  channels.

raw_content:
  ---
  tags: [logic-gates, binary, nand-to-tetris]
  ---

  # Multiplexers (MUX) and demultiplexers (DMUX)

  ## Multiplexer

  > Multiplexing is the generic term used to describe the operation of sending one
  > or more analogue or digital signals over a common transmission line at
  > different times or speeds.

  A multiplexer selects one of several input signals and forwards ths selected
  input to a single output line.

  We have two inputs (A,B) plus a third input SEL (for "select"). Applying a value
  to SEL toggles the output between A and B.

  ![](/img/MUX.png)

  Multiplexers can be used to build larger circuits by connecting the output of
  one multiplexer to the input of another. They are often used to implement data
  selection and switching in digital systems

  ### Programable gates

  One of the main use cases of multiplexers is to implement programmable gates.
  These are gates where the logic can be switched. For example an ANDMUXOR gate
  uses the SEL value to toggle the operation of a gate between AND and OR for its
  two inputs A and B

  ## Demultiplexer

  As the name suggests, a demultiplexer reverses the functionality of a
  multiplexer. It receives a single input and based on the selection of the SEL
  input it channels it to either an A or a B output.

  ![](/img/DMUX.png)

  We can think of it as a distributor of a value into one of several possible
  channels.


path: Multiplicative_identity.md
sortable_path: Multiplicative_identity.md
title: The Property of Multiplicative Identity
lead: **Let $a$ represent any member of $\mathbb{W}$ or $\mathbb{Z}$ then:**
body:
  **Let $a$ represent any member of $\mathbb{W}$ or $\mathbb{Z}$ then:**

  $$ a \cdot 1 = a $$

checksum: 52f24c40c400082277ab21ab5b035d11337ff52976576ef802044d363d17c6d0
created: 2024-10-22 16:52:57.916116886+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["prealgebra","theorems"]}
raw_content:
  ---
  tags:
    - prealgebra
    - theorems
  ---

  # The Property of Multiplicative Identity

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

  $$ a \cdot 1 = a $$


path: Multiplicative_property_of_negative_one.md
sortable_path: Multiplicative_property_of_negative_one.md
title: The Multiplicative Property of Negative One
lead: > **Let $a$ represent any member of $\mathbb{Z}$, then:**
body:
  > **Let $a$ represent any member of $\mathbb{Z}$, then:**

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

checksum: 3ea5a89ea5f9b12ba31084f176279eb700d16beb03d37584492c50100ba5a991
created: 2024-10-22 16:52:57.919819963+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["prealgebra","theorems"]}
raw_content:
  ---
  tags:
    - prealgebra
    - theorems
  ---

  # The Multiplicative Property of Negative One

  > **Let $a$ represent any member of $\mathbb{Z}$, then:**

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


path: Multiplying_fractions.md
sortable_path: Multiplying_fractions.md
title: Multiplying fractions
checksum: e693fb7d5cd07d76626f4e31e791a7cbb8bbd2effeb8cfe3169c7f2999b58136
created: 2024-10-22 16:52:57.923176425+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["prealgebra","fractions","arithmetic"]}
lead:
  To find the product of two fractions $\frac{a}{b}$ and $\frac{c}{d}$ multiply
  their numerators and denominators and then reduce:

body:
  To find the product of two fractions $\frac{a}{b}$ and $\frac{c}{d}$ multiply
  their numerators and denominators and then reduce:

  $$\frac{a}{b} \cdot \frac{c}{d} = \frac{a \cdot c}{b \cdot d}$$

  ### Example

  $$
  \frac{1}{3} \cdot \frac{2}{5} = \frac{1 \cdot 2}{3 \cdot 5} = \frac{2}{15}
  $$

  ## Prime factorisation in place

  The example above did not require a reduction, so here is a more complex
  example:

  $$
  \frac{14}{15} \cdot \frac{30}{140} = \frac{420}{2100}
  $$

  It would be laborious to reduce such a large product using factor trees or the
  repeated application of divisors, as defined in
  [reducing fractions](Reducing_fractions.md). We can use a more efficient
  method. This method can be applied at the point at which we conduct the
  multiplication rather than afterwards once we have the product. We express the
  the initial multiplicands as prime factors:

  $$
  \frac{14}{15} \cdot \frac{30}{140} = \frac{(2 \cdot 7) \cdot (2 \cdot 3 \cdot 5) }{(3 \cdot 5) \cdot (2 \cdot  2 \cdot 7 \cdot 5)}
  $$

  We now have the product in factorised form before we have applied the
  multiplication so we can go ahead and cancel:

  $$
  \frac{\cancel{2}, \cancel{7}, \cancel{2}, \cancel{3}, \cancel{5}}{\cancel{3}, \cancel{5}, \cancel{2}, \cancel{2}, \cancel{7}, 5} = \frac{1}{5}
  $$

  **Note that in the above case, there was only a single 5 left as a denominator
  and no value left as a numerator. This is equivalent to there just being "one
  five" so we write $\frac{1}{5}$**

  ## Example of multiplying fractions with negative fractions containing variables

  Calculate: $$- \frac{6x}{55y} \cdot - \frac{110y^2}{105x^2}$$

  First multiply in place:

  $$
  \frac{(3 \cdot 2 \cdot x) \cdot (5  \cdot 2 \cdot 11 \cdot y \cdot y)}{(5 \cdot 11 \cdot y) \cdot (7 \cdot 5 \cdot 3 \cdot x \cdot x)}
  $$

  Then cancel:

  $$
  \frac{(\cancel{3} \cdot 2 \cdot \cancel{x}) \cdot (\cancel{5}  \cdot 2 \cdot \cancel{11} \cdot \cancel{y} \cdot y)}{(\cancel{5} \cdot \cancel{11} \cdot \cancel{y}) \cdot (7 \cdot 5 \cdot \cancel{3} \cdot \cancel{x} \cdot x)} =
  \frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x}
  $$

  Then reduce:

  $$
  \frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x} = \frac{4y}{35x}
  $$

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

  # Multiplying fractions

  To find the product of two fractions $\frac{a}{b}$ and $\frac{c}{d}$ multiply
  their numerators and denominators and then reduce:

  $$\frac{a}{b} \cdot \frac{c}{d} = \frac{a \cdot c}{b \cdot d}$$

  ### Example

  $$
  \frac{1}{3} \cdot \frac{2}{5} = \frac{1 \cdot 2}{3 \cdot 5} = \frac{2}{15}
  $$

  ## Prime factorisation in place

  The example above did not require a reduction, so here is a more complex
  example:

  $$
  \frac{14}{15} \cdot \frac{30}{140} = \frac{420}{2100}
  $$

  It would be laborious to reduce such a large product using factor trees or the
  repeated application of divisors, as defined in
  [reducing fractions](Reducing_fractions.md). We can use a more efficient
  method. This method can be applied at the point at which we conduct the
  multiplication rather than afterwards once we have the product. We express the
  the initial multiplicands as prime factors:

  $$
  \frac{14}{15} \cdot \frac{30}{140} = \frac{(2 \cdot 7) \cdot (2 \cdot 3 \cdot 5) }{(3 \cdot 5) \cdot (2 \cdot  2 \cdot 7 \cdot 5)}
  $$

  We now have the product in factorised form before we have applied the
  multiplication so we can go ahead and cancel:

  $$
  \frac{\cancel{2}, \cancel{7}, \cancel{2}, \cancel{3}, \cancel{5}}{\cancel{3}, \cancel{5}, \cancel{2}, \cancel{2}, \cancel{7}, 5} = \frac{1}{5}
  $$

  **Note that in the above case, there was only a single 5 left as a denominator
  and no value left as a numerator. This is equivalent to there just being "one
  five" so we write $\frac{1}{5}$**

  ## Example of multiplying fractions with negative fractions containing variables

  Calculate: $$- \frac{6x}{55y} \cdot - \frac{110y^2}{105x^2}$$

  First multiply in place:

  $$
  \frac{(3 \cdot 2 \cdot x) \cdot (5  \cdot 2 \cdot 11 \cdot y \cdot y)}{(5 \cdot 11 \cdot y) \cdot (7 \cdot 5 \cdot 3 \cdot x \cdot x)}
  $$

  Then cancel:

  $$
  \frac{(\cancel{3} \cdot 2 \cdot \cancel{x}) \cdot (\cancel{5}  \cdot 2 \cdot \cancel{11} \cdot \cancel{y} \cdot y)}{(\cancel{5} \cdot \cancel{11} \cdot \cancel{y}) \cdot (7 \cdot 5 \cdot \cancel{3} \cdot \cancel{x} \cdot x)} =
  \frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x}
  $$

  Then reduce:

  $$
  \frac{2  \cdot 2 \cdot y}{7 \cdot 5 \cdot x} = \frac{4y}{35x}
  $$


path: Mutations_with_Apollo_Client.md
sortable_path: Mutations_with_Apollo_Client.md
title: Mutations with Apollo Client
lead: Queries are read-only operations. Mutations are write-only operations.
checksum: 1de70df0fe706eb5b212250f1aa7a3596e9b54cfc0587fcf729631b096a69d60
created: 2024-10-22 16:52:57.933751316+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["graphql"]}
body:
  Queries are read-only operations. Mutations are write-only operations.

  Just like the `Query` type, the `Mutation` type serves as an entrypoint to the
  schema.

  ## Naming convention

  - Use verb: `add`, `create`, `delete`
  - Refer to the datatype

  For example `addSpaceCat(){}`

  ## Demonstration mutation

  We are going to create a mutation that increments the `numberOfViews` field on
  the `Track` type:

  ## Updating the schema

  ```js
  type Mutation {
      incrementTrackViews(id: ID!): IncrementTrackViewsResponse!
  }


  // Define a specific response type that specifically matches our needs
  type IncrementTrackViewsResponse {
      code: Int! // status code
      success: Boolean! // whether mutation was successful
      message: String! // what to say if mutation successful
      track: Track   // not nullable because might error
  }
  ```

  Based on this schema, the mutation will recieve a `Track` id and increment the
  specified `Track`. It will return an object comprising the newly updated `Track`
  and a bundle of properties that provide feedback on the status of the
  operations: a status code, whether it succeeded, and a message.

  ## Updating the data source

  Remember that our sole data source in the demonstration project is a REST API.
  We handle it within GraphQL using Apollos `RESTDataSource` class. We need to add
  a method to this class that will increment the track views. We wil use the
  `PATCH` REST method:

  ```js
  class TrackAPI extends RESTDataSource {
    constructor() {...}
    getTracksForHome() {...}
    getAuthor(authorId) {...}
    getTrack(trackId){...};

    incrementTrackViews(trackId) {
      return this.patch(`track/${trackId}/numberOfViews`);
    }
  }
  ```

  The `patch()` method is procided by the `RESTDataSouce` class that `TrackAPI`
  inherits from

  ## Adding resolver

  Next we need a resolver that corresponds to the mutation we have defined in the
  schema. We will need to handle successful responses as well as errors.

  ### Success case

  As always we match the shape of the schema:

  ```js
  const resolvers = {
    Query: {
      // ...query resolvers
    },
    Mutation: {
      // increments a track's numberOfViews property
      incrementTrackViews: async (_, { id }, { dataSources }) => {
        const track = await dataSources.trackAPI.incrementTrackViews(id);
        return {
          code: 200,
          success: true,
          message: `Successfully incremented number of views for track ${id}`,
          track,
        };
      },
    },
  };
  ```

  There's more going on with this resolver than the previous one. As is standard,
  we call the API using the `TrackAPI` class. However we don't just immediately
  return this when it executes. This is because the schema specifies that the
  return type `IncrementTrackViewsResponse` requires more than just the updated
  `Track`. So we wait this and return it with the cluster of metadata about the
  mutation response (`code`, `success`, and `message`).

  ### Error case

  We can extend the Mutation resolver to allow for errors. We'll do this by
  refactoring the resolver into a `try...catch` block and adding the error
  handling in the `catch`.

  We'll harness the details that are provided by Apollos' own `err` object which
  is returned by the `RESTDataSource` class that our resolver ultimately traces
  back to:

  ```js
  const resolvers = {

      Query: {
          // ...query resolvers
      }

      Mutation: {
          incrementTrackViews: async (_, {id}, {dataSources}) => {
              try {
                  const track = await dataSources.trackAPI.incrementTrackViews(id);
                  return {
                      code: 200,
                      success: true,
                      message: `Successfully incremented number of views for track ${id}`,
                      track
                  };
              } catch (err) {
                  return {
                      code: err.extensions.response.status,
                      success: false,
                      message: err.extensions.response.body,
                      track: null
                  };
              }
          },
      }
  }
  ```

  ## The `useMutation` hook

  We invoke the `useMutation` hook to issue mutations from the client-side.

  As with queries and
  [query constants](Apollo_Client.md#query-constants) we
  wrap our mutation in a `gql` template string:

  ```js
  const INCREMENT_TRACK_VIEWS = gql`
    mutation IncrementTrackViews($incrementTrackViewsId: ID!) {
      incrementTrackViews(id: $incrementTrackViewsId) {
        code
        success
        message
        track {
          id
          numberOfViews
        }
      }
    }
  `;
  ```

  We then pass it to the `useMutation` hook including an options object with our
  variables. (This time the specific variable is named):

  ```js
  import { gql, useMutation } from "@apollo/client";

  useMutation(INCREMENT_TRACK_VIEWS, {
    variables: { incrementTrackViewsId: id },
  });
  ```

  `useMutation` returns an array of two elements:

  1. The mutation function that actually executes
  2. An object comprising (`loading`, `error`, `data`) - this is the same as is
     the return value of `useQuery`.

  So we can destructure like so (we don't always need the second element);

  ```js
  const [incrementTrackViews, dataObject] = useMutation(INCREMENT_TRACK_VIEWS...)
  ```

  Given that we can isolate the mutation function as the first destructured
  element of the array, we could then attach `incrementTrackViews` to a button or
  other frontend interaction.

raw_content:
  ---
  tags: [graphql]
  ---
  	
  # Mutations with Apollo Client

  Queries are read-only operations. Mutations are write-only operations.

  Just like the `Query` type, the `Mutation` type serves as an entrypoint to the
  schema.

  ## Naming convention

  - Use verb: `add`, `create`, `delete`
  - Refer to the datatype

  For example `addSpaceCat(){}`

  ## Demonstration mutation

  We are going to create a mutation that increments the `numberOfViews` field on
  the `Track` type:

  ## Updating the schema

  ```js
  type Mutation {
      incrementTrackViews(id: ID!): IncrementTrackViewsResponse!
  }


  // Define a specific response type that specifically matches our needs
  type IncrementTrackViewsResponse {
      code: Int! // status code
      success: Boolean! // whether mutation was successful
      message: String! // what to say if mutation successful
      track: Track   // not nullable because might error
  }
  ```

  Based on this schema, the mutation will recieve a `Track` id and increment the
  specified `Track`. It will return an object comprising the newly updated `Track`
  and a bundle of properties that provide feedback on the status of the
  operations: a status code, whether it succeeded, and a message.

  ## Updating the data source

  Remember that our sole data source in the demonstration project is a REST API.
  We handle it within GraphQL using Apollos `RESTDataSource` class. We need to add
  a method to this class that will increment the track views. We wil use the
  `PATCH` REST method:

  ```js
  class TrackAPI extends RESTDataSource {
    constructor() {...}
    getTracksForHome() {...}
    getAuthor(authorId) {...}
    getTrack(trackId){...};

    incrementTrackViews(trackId) {
      return this.patch(`track/${trackId}/numberOfViews`);
    }
  }
  ```

  The `patch()` method is procided by the `RESTDataSouce` class that `TrackAPI`
  inherits from

  ## Adding resolver

  Next we need a resolver that corresponds to the mutation we have defined in the
  schema. We will need to handle successful responses as well as errors.

  ### Success case

  As always we match the shape of the schema:

  ```js
  const resolvers = {
    Query: {
      // ...query resolvers
    },
    Mutation: {
      // increments a track's numberOfViews property
      incrementTrackViews: async (_, { id }, { dataSources }) => {
        const track = await dataSources.trackAPI.incrementTrackViews(id);
        return {
          code: 200,
          success: true,
          message: `Successfully incremented number of views for track ${id}`,
          track,
        };
      },
    },
  };
  ```

  There's more going on with this resolver than the previous one. As is standard,
  we call the API using the `TrackAPI` class. However we don't just immediately
  return this when it executes. This is because the schema specifies that the
  return type `IncrementTrackViewsResponse` requires more than just the updated
  `Track`. So we wait this and return it with the cluster of metadata about the
  mutation response (`code`, `success`, and `message`).

  ### Error case

  We can extend the Mutation resolver to allow for errors. We'll do this by
  refactoring the resolver into a `try...catch` block and adding the error
  handling in the `catch`.

  We'll harness the details that are provided by Apollos' own `err` object which
  is returned by the `RESTDataSource` class that our resolver ultimately traces
  back to:

  ```js
  const resolvers = {

      Query: {
          // ...query resolvers
      }

      Mutation: {
          incrementTrackViews: async (_, {id}, {dataSources}) => {
              try {
                  const track = await dataSources.trackAPI.incrementTrackViews(id);
                  return {
                      code: 200,
                      success: true,
                      message: `Successfully incremented number of views for track ${id}`,
                      track
                  };
              } catch (err) {
                  return {
                      code: err.extensions.response.status,
                      success: false,
                      message: err.extensions.response.body,
                      track: null
                  };
              }
          },
      }
  }
  ```

  ## The `useMutation` hook

  We invoke the `useMutation` hook to issue mutations from the client-side.

  As with queries and
  [query constants](Apollo_Client.md#query-constants) we
  wrap our mutation in a `gql` template string:

  ```js
  const INCREMENT_TRACK_VIEWS = gql`
    mutation IncrementTrackViews($incrementTrackViewsId: ID!) {
      incrementTrackViews(id: $incrementTrackViewsId) {
        code
        success
        message
        track {
          id
          numberOfViews
        }
      }
    }
  `;
  ```

  We then pass it to the `useMutation` hook including an options object with our
  variables. (This time the specific variable is named):

  ```js
  import { gql, useMutation } from "@apollo/client";

  useMutation(INCREMENT_TRACK_VIEWS, {
    variables: { incrementTrackViewsId: id },
  });
  ```

  `useMutation` returns an array of two elements:

  1. The mutation function that actually executes
  2. An object comprising (`loading`, `error`, `data`) - this is the same as is
     the return value of `useQuery`.

  So we can destructure like so (we don't always need the second element);

  ```js
  const [incrementTrackViews, dataObject] = useMutation(INCREMENT_TRACK_VIEWS...)
  ```

  Given that we can isolate the mutation function as the first destructured
  element of the array, we could then attach `incrementTrackViews` to a button or
  other frontend interaction.


path: Naming_conventions.md
sortable_path: Naming_conventions.md
title: Python naming conventions
lead: ## Underscores
checksum: f491ff1235bf5bb1a424568b00d219bbb0760f8c2b82962ba863401322fbac87
created: 2024-10-22 16:52:57.939890724+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["python"]}
body:
  ## Underscores

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

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

  ## Constants

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

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

  # Python naming conventions

  ## Underscores

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

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

  ## Constants

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


path: Natural_numbers.md
sortable_path: Natural_numbers.md
title: Natural numbers
lead: ## The set of natural numbers
checksum: 7efc4b198d7fcaf01e4bda93b0f3898b0820ee491fe04ffed59f192c44177e63
created: 2024-10-22 16:52:57.94471092+00:00
modified: 2024-10-18 18:17:38.24720807+00:00
metadata: {"tags":["prealgebra"]}
body:
  ## The set of natural numbers

  $$ \mathbb{N} = {1, 2, 3, ...} $$

  Natural numbers are most simply expressed as **the set of numbers we use for
  counting**. The set of natural numbers start at one and continuity to infinity.

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

  # Natural numbers

  ## The set of natural numbers

  $$ \mathbb{N} = {1, 2, 3, ...} $$

  Natural numbers are most simply expressed as **the set of numbers we use for
  counting**. The set of natural numbers start at one and continuity to infinity.


path: Negation_Elimination.md
sortable_path: Negation_Elimination.md
title: Negation Elimination
checksum: 7d0d8a02311c15474ed12c7515ca6737cc8a23152c106636d6ba9197ad5c8596
created: 2024-10-22 16:52:57.950012881+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["logic","propositional-logic"]}
lead:
  Like the [introduction](Negation_Introduction.md) rule for
  negation, the elimination rule also works by deriving a contradiction. It is
  basically _Negation Introduction_ in reverse. Instead of starting the sub-proof
  with a true proposition from which you derive a contradiction, you start with
  the negation of a proposition, derive a contradiction and then assert the
  positive of the negated proposition you started out with.

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

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

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

  # Negation Elimination

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

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


path: Negation_Introduction.md
sortable_path: Negation_Introduction.md
title: Negation Introduction
checksum: d60e1513c026e4684b3285bf1af37e05e071a19a13e398ba5277532d38ee90cd
created: 2024-10-22 16:52:57.960607306+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["logic","propositional-logic"]}
lead:
  This is also known as _proof by contradiction_. You start with an assumption
  declared in a sub-proof. If you can derive a contradiction from this assumption
  (typically from the introduction of another proposition and its negation), then
  you are permitted to derive the negation of the auxiliary assumption in the main
  proof.

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

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

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

  # Negation Introduction

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

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


path: Negative_exponents.md
sortable_path: Negative_exponents.md
title: Negative exponents
lead:
  When calculating the exponents of a negative number the answer will always will
  be positive:

checksum: 09c48c27a5b3a332373c87afbd54f52a46d92b0637e5b788c2135c0adfb13834
created: 2024-10-22 16:52:57.965267264+00:00
modified: 2024-10-18 18:17:49.140745007+00:00
metadata: {"tags":["algebra","exponents"]}
body:
  When calculating the exponents of a negative number the answer will always will
  be positive:

  $$
  -5^2 = 25
  $$

  This confused me but it was because I was thinking of it in terms of
  $-5 \cdot 5$ when in fact it is $-5 \cdot -5$ and when two negative numbers are
  multiplied the product is always negative.

raw_content:
  ---
  tags: [algebra, exponents]
  ---

  # Negative exponents

  When calculating the exponents of a negative number the answer will always will
  be positive:

  $$
  -5^2 = 25
  $$

  This confused me but it was because I was thinking of it in terms of
  $-5 \cdot 5$ when in fact it is $-5 \cdot -5$ and when two negative numbers are
  multiplied the product is always negative.


path: Network_card.md
sortable_path: Network_card.md
title: Network card
checksum: 76c1d9ecb72c7e71e23119bd1159d51e40a3a9da798a073ba9888eddeedad437
created: 2024-10-22 16:52:57.969594554+00:00
modified: 2024-10-18 18:18:10.66781386+00:00
metadata: {"created":"Tuesday, August 06, 2024","tags":["networks","hardware"]}
lead:
  The network card (technically know as the Network Interface Card (NIC)) or
  _network adapter_ is the hardware device that allows a computer to connect to a
  network.

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

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

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

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

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

raw_content:
  ---
  tags: [networks, hardware]
  created: Tuesday, August 06, 2024
  ---

  # Network card

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

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

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

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

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


path: Network_debugging.md
sortable_path: Network_debugging.md
title: Network debugging
lead: ## Related notes
body:
  ## Related notes

  ![Network scanning](Network_scanning.md)

checksum: b18f726199d234e7e7f8592d035aba3e276a636627c070c18a07d9b6211d9698
created: 2024-10-22 16:52:57.983789938+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"created":"Monday, June 17, 2024","id":"x44w","tags":["procedural","Linux","networks"]}
raw_content:
  ---
  id: x44w
  tags: [procedural, Linux, networks]
  created: Monday, June 17, 2024
  ---

  # Network debugging

  ## Related notes

  ![Network scanning](Network_scanning.md)


path: Network_fundamentals.md
sortable_path: Network_fundamentals.md
title: Network fundamentals
checksum: cc82f0dcd8355ab2f7af5eda572679f060a725888b69ea268ca70bdaacb8a794
created: 2024-10-22 16:52:57.988994481+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"created":"Saturday, August 03, 2024","tags":["networks","network-protocols"]}
lead:
  > A network is a system that allows computing devices to communicate and
  > exchange information with each other.

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

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

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

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

raw_content:
  ---
  tags: [networks, network-protocols]
  created: Saturday, August 03, 2024
  ---

  # Network fundamentals

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

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

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

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


path: Network_hosts.md
sortable_path: Network_hosts.md
title: Network hosts
checksum: b4ac6a2c1a8d9cbdeb0ebd886484e545c5d398dfb3ef09c0c4aa8380b3d430f1
created: 2024-10-22 16:52:57.999801411+00:00
modified: 2024-10-18 18:18:24.428070835+00:00
metadata: {"created":"Saturday, August 03, 2024","tags":["networks"]}
lead:
  A network **host** or **node** is a single computing device attached to a
  ![network](Network_fundamentals.md)

body:
  A network **host** or **node** is a single computing device attached to a
  ![network](Network_fundamentals.md)

  Hosts can act as servers or clients, or both.

  ## Server

  A network server is a host that listens for inbound network connections and
  provides services to other hosts. Examples include web and email servers.

  ## Client

  A network client is a host that makes outbound connections and requests servcies
  from network servers.

raw_content:
  ---
  tags: [networks]
  created: Saturday, August 03, 2024
  ---

  # Network hosts

  A network **host** or **node** is a single computing device attached to a
  ![network](Network_fundamentals.md)

  Hosts can act as servers or clients, or both.

  ## Server

  A network server is a host that listens for inbound network connections and
  provides services to other hosts. Examples include web and email servers.

  ## Client

  A network client is a host that makes outbound connections and requests servcies
  from network servers.


path: Network_protocols.md
sortable_path: Network_protocols.md
title: Network protocols
checksum: 25b22a05f48950de12dbb593e2bde94b3da329d5b20dec546c4b3624f40f3767
created: 2024-10-22 16:52:58.00458005+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"created":"Saturday, August 03, 2024","tags":["networks"]}
lead:
  Protocols are agreed standards specifying and governing communication between
  nodes on a [network](Network_fundamentals.md).

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

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

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

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

raw_content:
  ---
  tags: [networks]
  created: Saturday, August 03, 2024
  ---

  # Network protocols

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

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

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

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


path: Network_requests_in_Python.md
sortable_path: Network_requests_in_Python.md
title: Making network requests in Python
checksum: f3c9fa4c90fc5f9c3658fb0d8b0127b1faab85a129c65a5242078c2edc0dfb3a
created: 2024-10-22 16:52:58.015631289+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["python","APIs","networks"]}
lead:
  We can use the `requests` package to make API requests to
  [RESTful](RESTful_APIs.md) resources and handle the data as JSON.

body:
  We can use the `requests` package to make API requests to
  [RESTful](RESTful_APIs.md) resources and handle the data as JSON.

  ```sh
  pip install requests
  ```

  Here is a basic architecture for making a `GET` request in Python.

  ```python
  import requests

  def get_data(url):
      response = requests.get(url)
      if response.status_code == 200:
          return response.json()
      else:
          raise Exception(
              f"Failed to fetch data from API. Status code: {response.status_code}")

  def main():
      url = "https://dummyjson.com/products/1"

      try:
          data = get_data(url)
          print(data)

      except Exception as e:
          prin(e)

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

  ## Parsing returned data

  Running `main` returns:

  ```python
  {
     "id":1,
     "title":"iPhone 9",
     "description":"An apple mobile which is nothing like apple",
     "price":549,
     "discountPercentage":12.96,
     "rating":4.69,
     "stock":94,
     "brand":"Apple",
     "category":"smartphones",
     "thumbnail":"https://i.dummyjson.com/data/products/1/thumbnail.jpg",
     "images":[
        "https://i.dummyjson.com/data/products/1/1.jpg",
        "https://i.dummyjson.com/data/products/1/2.jpg",
        "https://i.dummyjson.com/data/products/1/3.jpg",
        "https://i.dummyjson.com/data/products/1/4.jpg",
        "https://i.dummyjson.com/data/products/1/thumbnail.jpg"
     ]
  }
  ```

  This is JSON but in Python is a [dictionary](Dictionaries_in_Python.md)

  We can use standard dictionary methods to handle the data. For example, we'll
  add to the existing `try` block:

  ```python
  example_key = "brand"  # Replace with the key you want to access from the JSON data
      if example_key in data:
          print(f"Value of '{example_key}':", data[example_key])
      else:
          print(f"'{example_key}' not found in the JSON data")
  ```

  Which, if successful, outputs:

  ```
  Value of 'brand': Apple
  ```

raw_content:
  ---
  tags:
    - python
    - APIs
    - networks
  ---

  # Making network requests in Python

  We can use the `requests` package to make API requests to
  [RESTful](RESTful_APIs.md) resources and handle the data as JSON.

  ```sh
  pip install requests
  ```

  Here is a basic architecture for making a `GET` request in Python.

  ```python
  import requests

  def get_data(url):
      response = requests.get(url)
      if response.status_code == 200:
          return response.json()
      else:
          raise Exception(
              f"Failed to fetch data from API. Status code: {response.status_code}")

  def main():
      url = "https://dummyjson.com/products/1"

      try:
          data = get_data(url)
          print(data)

      except Exception as e:
          prin(e)

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

  ## Parsing returned data

  Running `main` returns:

  ```python
  {
     "id":1,
     "title":"iPhone 9",
     "description":"An apple mobile which is nothing like apple",
     "price":549,
     "discountPercentage":12.96,
     "rating":4.69,
     "stock":94,
     "brand":"Apple",
     "category":"smartphones",
     "thumbnail":"https://i.dummyjson.com/data/products/1/thumbnail.jpg",
     "images":[
        "https://i.dummyjson.com/data/products/1/1.jpg",
        "https://i.dummyjson.com/data/products/1/2.jpg",
        "https://i.dummyjson.com/data/products/1/3.jpg",
        "https://i.dummyjson.com/data/products/1/4.jpg",
        "https://i.dummyjson.com/data/products/1/thumbnail.jpg"
     ]
  }
  ```

  This is JSON but in Python is a [dictionary](Dictionaries_in_Python.md)

  We can use standard dictionary methods to handle the data. For example, we'll
  add to the existing `try` block:

  ```python
  example_key = "brand"  # Replace with the key you want to access from the JSON data
      if example_key in data:
          print(f"Value of '{example_key}':", data[example_key])
      else:
          print(f"'{example_key}' not found in the JSON data")
  ```

  Which, if successful, outputs:

  ```
  Value of 'brand': Apple
  ```


path: Network_scanning.md
sortable_path: Network_scanning.md
title: Network scanning
lead: ## List all connected devices on local WiFi network
checksum: a1117fe7c76323a1b2af2c2f9b47e0dc0000d75f045daa4530791b61c6e3fee4
created: 2024-10-22 16:52:58.028759233+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"created":"Monday, June 10, 2024","id":"ippn","tags":["networks","procedural","Linux"]}
body:
  ## 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
  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
  ```


path: NodeJS_scripts.md
sortable_path: NodeJS_scripts.md
title: NodeJS scripts
checksum: f65f2dc24fc46bb1d9ca1d4266aa146052074c8d179694d74c3832d5da363e0d
created: 2024-10-22 16:52:58.03366293+00:00
modified: 2024-10-18 18:18:42.791746991+00:00
metadata: {"created":"Friday, April 26, 2024","tags":["node-js"]}
lead:
  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.

body:
  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:
  ---
  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: Node_and_MySQL_db.md
sortable_path: Node_and_MySQL_db.md
title: Docker example: NodeJS backend with MySQL database
lead:
  We will utilise [Docker Compose](Docker_Compose.md) to combine
  two containers:

checksum: da18db716656813a6f25424eb45c5c29a3af3b45d1c3d300c401e507e2154925
created: 2024-10-22 16:52:58.038461184+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["docker","SQL","node-js","databases"]}
body:
  We will utilise [Docker Compose](Docker_Compose.md) to combine
  two containers:

  - A container for the NodeJS backend
  - A container for the MySQL database

  We will only create a Dockerfile for the NodeJS part since the existing `mysql`
  image is sufficient for most needs and does not require a specific
  configuration.

  Each of the files listed below would be saved to the same source directory which
  would then form the basis of the
  [build context](Creating_a_Docker_image.md#creating-a-docker-image).

  ## Docker Compose file

  ```yml
  # docker-compose.yml
  version: "3.8"
  services:
    db:
      image: mysql:8.0
      container_name: mysql_container
      environment:
        MYSQL_ROOT_PASSWORD: your_root_password
        MYSQL_DATABASE: your_database_name
        MYSQL_USER: your_database_user
        MYSQL_PASSWORD: your_database_password
      volumes:
        - mysql-data:/var/lib/mysql
      ports:
        - "3306:3306"
    app:
      build: .
      container_name: node_app
      volumes:
        - .:/usr/src/app
      environment:
        MYSQL_HOST: db
        MYSQL_USER: your_database_user
        MYSQL_PASSWORD: your_database_password
        MYSQL_DB: your_database_name
      depends_on:
        - db
      ports:
        - "3000:3000"

  volumes:
    mysql-data:
  ```

  ## Dockerfile for the NodeJS backend

  ```Dockerfile
  # Dockerfile
  FROM node:14

  WORKDIR /usr/src/app

  COPY package*.json ./

  RUN npm install

  COPY . .

  EXPOSE 3000

  CMD [ "node", "app.js" ]
  ```

  ## NodeJS project setup

  ```json
  // package.json
  {
    "name": "node-mysql-docker",
    "version": "1.0.0",
    "description": "Node.js and MySQL with Docker",
    "main": "app.js",
    "scripts": {
      "start": "node app.js"
    },
    "dependencies": {
      "express": "^4.17.1",
      "mysql2": "^2.3.2"
    }
  }
  ```

  ```js
  // app.js
  const express = require("express");
  const mysql = require("mysql2/promise");

  const app = express();

  const { MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB } = process.env;

  const createConnection = async () => {
    return await mysql.createConnection({
      host: MYSQL_HOST,
      user: MYSQL_USER,
      password: MYSQL_PASSWORD,
      database: MYSQL_DB,
    });
  };

  app.get("/", async (req, res) => {
    const connection = await createConnection();
    const [rows] = await connection.query("SELECT 1 + 1 AS solution");
    res.send(`Hello World! The solution is ${rows[0].solution}`);
  });

  const PORT = 3000;
  app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
  });
  ```

  To start up the environment you would then run:

  ```
  docker-compose -up
  ```

  ## Environments

  In the example, the database connection information in the Node source is coming
  from the
  [`process.env`](Managing_environments_in_NodeJS.md)
  object, which itself is sourcing the values `MYSQL_HOST`, `MYSQL_PASSWORD` etc
  from the Docker compose file. Therefore these values are hardcoded there.

  This is not good practice as it exposes sensitive information and make managing
  different deployment environments (development, stage, test etc.) difficult.

  To get around this we would create an `.env` file in the project directory that
  is Git ignored:

  ```sh
  # .env
  MYSQL_ROOT_PASSWORD=your_root_password
  MYSQL_DATABASE=your_database_name
  MYSQL_USER=your_database_user
  MYSQL_PASSWORD=your_database_password
  ```

  Then the `docker-compose.yml` file can be updated to use these variables:

  ```yml
  version: "3.8"
  services:
    db:
      image: mysql:8.0
      container_name: mysql_container
      environment:
        MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
        MYSQL_DATABASE: ${MYSQL_DATABASE}
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      volumes:
        - mysql-data:/var/lib/mysql
      ports:
        - "3306:3306"
    app:
      build: .
      container_name: node_app
      volumes:
        - .:/usr/src/app
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
      depends_on:
        - db
      ports:
        - "3000:3000"

  volumes:
    mysql-data:
  ```

  `${VARIABLE_NAME}` syntax is used to reference environment variables from the
  .env file in the `docker-compose.yml` file. Docker Compose will automatically
  load the variables from the .env file when starting the services.

  ### Development, staging, production environments

  To specify different connection details for different environments you would
  create different `.env` files for each:

  - `.env.development`
  - `.env.staging`
  - `.env.production`

  Each file will contain **environment-specific variables**, such as database
  credentials, API keys, and other configuration details.

  For example, development and production:

  ```yml
  # docker-compose.development.yml
  version: '3.8'
  services:
    db:
      ...
    app:
      ...
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
        NODE_ENV: development

  ```

  ```yml
  # docker-compose.production.yml
  version: '3.8'
  services:
    db:
      ...
    app:
      ...
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
        NODE_ENV: production
  `
  ```

  Then you would select the specific environment with your run command:

  ```
  docker-compose -f docker-compose.development.yml up -d
  ```

  Docker won't know by default which `.env` file to use from that command however.
  Assuming all the files are in the same directory you can use Bash substitution
  to specify the source of the environment specific variables:

  ```sh
  export $(cat .env.development | xargs) && docker-compose -f docker-compose.development.yml up -d
  ```

raw_content:
  ---
  tags:
    - docker
    - SQL
    - node-js
    - databases
  ---

  # Docker example: NodeJS backend with MySQL database

  We will utilise [Docker Compose](Docker_Compose.md) to combine
  two containers:

  - A container for the NodeJS backend
  - A container for the MySQL database

  We will only create a Dockerfile for the NodeJS part since the existing `mysql`
  image is sufficient for most needs and does not require a specific
  configuration.

  Each of the files listed below would be saved to the same source directory which
  would then form the basis of the
  [build context](Creating_a_Docker_image.md#creating-a-docker-image).

  ## Docker Compose file

  ```yml
  # docker-compose.yml
  version: "3.8"
  services:
    db:
      image: mysql:8.0
      container_name: mysql_container
      environment:
        MYSQL_ROOT_PASSWORD: your_root_password
        MYSQL_DATABASE: your_database_name
        MYSQL_USER: your_database_user
        MYSQL_PASSWORD: your_database_password
      volumes:
        - mysql-data:/var/lib/mysql
      ports:
        - "3306:3306"
    app:
      build: .
      container_name: node_app
      volumes:
        - .:/usr/src/app
      environment:
        MYSQL_HOST: db
        MYSQL_USER: your_database_user
        MYSQL_PASSWORD: your_database_password
        MYSQL_DB: your_database_name
      depends_on:
        - db
      ports:
        - "3000:3000"

  volumes:
    mysql-data:
  ```

  ## Dockerfile for the NodeJS backend

  ```Dockerfile
  # Dockerfile
  FROM node:14

  WORKDIR /usr/src/app

  COPY package*.json ./

  RUN npm install

  COPY . .

  EXPOSE 3000

  CMD [ "node", "app.js" ]
  ```

  ## NodeJS project setup

  ```json
  // package.json
  {
    "name": "node-mysql-docker",
    "version": "1.0.0",
    "description": "Node.js and MySQL with Docker",
    "main": "app.js",
    "scripts": {
      "start": "node app.js"
    },
    "dependencies": {
      "express": "^4.17.1",
      "mysql2": "^2.3.2"
    }
  }
  ```

  ```js
  // app.js
  const express = require("express");
  const mysql = require("mysql2/promise");

  const app = express();

  const { MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB } = process.env;

  const createConnection = async () => {
    return await mysql.createConnection({
      host: MYSQL_HOST,
      user: MYSQL_USER,
      password: MYSQL_PASSWORD,
      database: MYSQL_DB,
    });
  };

  app.get("/", async (req, res) => {
    const connection = await createConnection();
    const [rows] = await connection.query("SELECT 1 + 1 AS solution");
    res.send(`Hello World! The solution is ${rows[0].solution}`);
  });

  const PORT = 3000;
  app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
  });
  ```

  To start up the environment you would then run:

  ```
  docker-compose -up
  ```

  ## Environments

  In the example, the database connection information in the Node source is coming
  from the
  [`process.env`](Managing_environments_in_NodeJS.md)
  object, which itself is sourcing the values `MYSQL_HOST`, `MYSQL_PASSWORD` etc
  from the Docker compose file. Therefore these values are hardcoded there.

  This is not good practice as it exposes sensitive information and make managing
  different deployment environments (development, stage, test etc.) difficult.

  To get around this we would create an `.env` file in the project directory that
  is Git ignored:

  ```sh
  # .env
  MYSQL_ROOT_PASSWORD=your_root_password
  MYSQL_DATABASE=your_database_name
  MYSQL_USER=your_database_user
  MYSQL_PASSWORD=your_database_password
  ```

  Then the `docker-compose.yml` file can be updated to use these variables:

  ```yml
  version: "3.8"
  services:
    db:
      image: mysql:8.0
      container_name: mysql_container
      environment:
        MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
        MYSQL_DATABASE: ${MYSQL_DATABASE}
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      volumes:
        - mysql-data:/var/lib/mysql
      ports:
        - "3306:3306"
    app:
      build: .
      container_name: node_app
      volumes:
        - .:/usr/src/app
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
      depends_on:
        - db
      ports:
        - "3000:3000"

  volumes:
    mysql-data:
  ```

  `${VARIABLE_NAME}` syntax is used to reference environment variables from the
  .env file in the `docker-compose.yml` file. Docker Compose will automatically
  load the variables from the .env file when starting the services.

  ### Development, staging, production environments

  To specify different connection details for different environments you would
  create different `.env` files for each:

  - `.env.development`
  - `.env.staging`
  - `.env.production`

  Each file will contain **environment-specific variables**, such as database
  credentials, API keys, and other configuration details.

  For example, development and production:

  ```yml
  # docker-compose.development.yml
  version: '3.8'
  services:
    db:
      ...
    app:
      ...
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
        NODE_ENV: development

  ```

  ```yml
  # docker-compose.production.yml
  version: '3.8'
  services:
    db:
      ...
    app:
      ...
      environment:
        MYSQL_HOST: db
        MYSQL_USER: ${MYSQL_USER}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        MYSQL_DB: ${MYSQL_DATABASE}
        NODE_ENV: production
  `
  ```

  Then you would select the specific environment with your run command:

  ```
  docker-compose -f docker-compose.development.yml up -d
  ```

  Docker won't know by default which `.env` file to use from that command however.
  Assuming all the files are in the same directory you can use Bash substitution
  to specify the source of the environment specific variables:

  ```sh
  export $(cat .env.development | xargs) && docker-compose -f docker-compose.development.yml up -d
  ```


path: Nodemon.md
sortable_path: Nodemon.md
title: Nodemon
checksum: 223c81e0636c8f7c17244cad0b4e2dc871021f2954688aa7f70ee67f8a2d6bfb
created: 2024-10-22 16:52:58.053980058+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["node-js"]}
lead:
  We don't want to have to restart the local server every time we make a change to
  our files. We can use `nodemon` instead of `node` when running our `index.js`
  file so that file-changes are immediately registered without the need for a
  restart.

body:
  We don't want to have to restart the local server every time we make a change to
  our files. We can use `nodemon` instead of `node` when running our `index.js`
  file so that file-changes are immediately registered without the need for a
  restart.

  This is a wrapper around the `node` command so it doesn't require any
  configuration. Once installed, update your start script from `node index.js` to
  `nodemon index.js`.

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

  # Nodemon

  We don't want to have to restart the local server every time we make a change to
  our files. We can use `nodemon` instead of `node` when running our `index.js`
  file so that file-changes are immediately registered without the need for a
  restart.

  This is a wrapper around the `node` command so it doesn't require any
  configuration. Once installed, update your start script from `node index.js` to
  `nodemon index.js`.


path: Non_null_assertion_in_TypeScript.md
sortable_path: Non_null_assertion_in_TypeScript.md
title: Non-null assertion
lead: Oftentimes you will encounter errors of the form:
checksum: 3afb6d654d3d9d9c24f9155a366976af6b70dc7f501848f73c2cb17e7c8e6455
created: 2024-10-22 16:52:58.059301628+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["typescript"]}
body:
  Oftentimes you will encounter errors of the form:

  `Property [property_name] does not exist on type [type_name].ts(2339)`

  This means the interpreter is not able to determine whether the property which
  you are seeking to change exists. It can't be sure that you are not trying to
  update a property that is either `null` or `undefined`. This is good type
  checking but it means that in cases when _you know_ the property either exists
  or _will_ exist at runtime, you are going to face a code-breaking error.

  To get around this you can use non-null assertion. Like the name suggests, here
  you are saying to TypeScript: thanks but I am sure this property exists. When
  you do this you get the value you are trying to change with `null` and
  `undefined` excluded from it.

  This typically occurs when you are assigning a property to a value and TS
  doesn't know whether the value will exist or be accessible at this point in the
  runtime. A good scenario would be dynamic data passed into a function:

  ```ts
  function doSomethingWith(typeAlias: ITypeAlias) {
    let x = typeAlias!.somePropertyEvidentAtRuntime;
  }
  ```

  However it should be used carefully and sparingly because you are obviously
  turning off core type-checking and overuse nullifies the purpose of TypeScript.

  One way to get around it is to use better
  [type-guarding](Type_guarding_and_narrowing.md) and conditionality and to
  cover cases where the value may be undefined.

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

  # Non-null assertion

  Oftentimes you will encounter errors of the form:

  `Property [property_name] does not exist on type [type_name].ts(2339)`

  This means the interpreter is not able to determine whether the property which
  you are seeking to change exists. It can't be sure that you are not trying to
  update a property that is either `null` or `undefined`. This is good type
  checking but it means that in cases when _you know_ the property either exists
  or _will_ exist at runtime, you are going to face a code-breaking error.

  To get around this you can use non-null assertion. Like the name suggests, here
  you are saying to TypeScript: thanks but I am sure this property exists. When
  you do this you get the value you are trying to change with `null` and
  `undefined` excluded from it.

  This typically occurs when you are assigning a property to a value and TS
  doesn't know whether the value will exist or be accessible at this point in the
  runtime. A good scenario would be dynamic data passed into a function:

  ```ts
  function doSomethingWith(typeAlias: ITypeAlias) {
    let x = typeAlias!.somePropertyEvidentAtRuntime;
  }
  ```

  However it should be used carefully and sparingly because you are obviously
  turning off core type-checking and overuse nullifies the purpose of TypeScript.

  One way to get around it is to use better
  [type-guarding](Type_guarding_and_narrowing.md) and conditionality and to
  cover cases where the value may be undefined.


path: None_in_Python.md
sortable_path: None_in_Python.md
title: None in Python
checksum: 185fdbfe796eb95a3ec84eab881a101129a444faade8c2bc76b831840d9c8a1b
created: 2024-10-22 16:52:58.071515263+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["python","data-types"]}
lead:
  `None` is not `null`, it is closer to `undefined` in JS. If you define a
  variable as `None`, the variable exists, it is just not yet defined.

body:
  `None` is not `null`, it is closer to `undefined` in JS. If you define a
  variable as `None`, the variable exists, it is just not yet defined.

  Using `None` is a pattern similar to using `let` in JS to name a variable and
  definine it later on.

  ```python
  temperature = None
  ```

  If we logged `temperature` it would give us `None` rather than a null pointer
  error.

  With None we can use `is None` and `is not None`, special predicates for working
  with `None` only. This is a akin to using `if (x !== undefined)` in TypeScript

  ```python
  winner = None
  print('winner:', winner)
  # winner: None
  print('winner is None:', winner is None)
  # winner is None: True
  print('winner is not None:', winner is not None)
  # winner is not None: False
  print(type(winner))
  # <class 'NoneType'>
  # Now set winner to be True
  print('Set winner to True')
  # Set winner to True
  winner = True
  print('winner:', winner)
  # winner: True
  print('winner is None:', winner is None)
  # winner is None: False
  print('winner is not None:', winner is not None)
  # winner is not None: True
  print(type(winner))
  # <class 'bool'>
  ```

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

  # None in Python

  `None` is not `null`, it is closer to `undefined` in JS. If you define a
  variable as `None`, the variable exists, it is just not yet defined.

  Using `None` is a pattern similar to using `let` in JS to name a variable and
  definine it later on.

  ```python
  temperature = None
  ```

  If we logged `temperature` it would give us `None` rather than a null pointer
  error.

  With None we can use `is None` and `is not None`, special predicates for working
  with `None` only. This is a akin to using `if (x !== undefined)` in TypeScript

  ```python
  winner = None
  print('winner:', winner)
  # winner: None
  print('winner is None:', winner is None)
  # winner is None: True
  print('winner is not None:', winner is not None)
  # winner is not None: False
  print(type(winner))
  # <class 'NoneType'>
  # Now set winner to be True
  print('Set winner to True')
  # Set winner to True
  winner = True
  print('winner:', winner)
  # winner: True
  print('winner is None:', winner is None)
  # winner is None: False
  print('winner is not None:', winner is not None)
  # winner is not None: True
  print(type(winner))
  # <class 'bool'>
  ```


path: Numbers_in_Python.md
sortable_path: Numbers_in_Python.md
title: Numbers in Python
lead: ## Distinguishing `int` and `float`
checksum: 7686d82f635d53fb6d4a45f128d97422a6636463c04c96174ff31bbcbd339c69
created: 2024-10-22 16:52:58.076311248+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["python","data-types"]}
body:
  ## Distinguishing `int` and `float`

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

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

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

  print(float(count))
  # 1.0

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

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

  # Numbers in Python

  ## Distinguishing `int` and `float`

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

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

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

  print(float(count))
  # 1.0

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


path: Object_language_and_meta_language.md
sortable_path: Object_language_and_meta_language.md
title: Object and metalanguages
checksum: 1be63bc78982eb0666e64209842912123a849dc70adfa066275c571ce3350c22
created: 2024-10-22 16:52:58.082048671+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["propositional-logic","logic"]}
lead:
  When we talk about a language we call that language the **object language**. A
  **metalanguage** is a language used to describe some object language.

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

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

  **Demonstration**

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

  ## Use and mention

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

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

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

  ## Metavariables

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

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

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

  # Object and metalanguages

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

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

  **Demonstration**

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

  ## Use and mention

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

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

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

  ## Metavariables

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

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


path: Observer_pattern.md
sortable_path: Observer_pattern.md
title: Observer pattern
lead: The Observer design pattern is also known as the 'publish/subscribe' pattern.
checksum: 30dcbcaeaa06659911bb025762903a012710c53a980c163c8a78719369222dba
created: 2024-10-22 16:52:58.085137396+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["OOP","design-patterns"]}
body:
  The Observer design pattern is also known as the 'publish/subscribe' pattern.

  > The observer pattern is a software design pattern in which an object, called
  > the subject, maintains a list of its dependents, called observers, and
  > notifies them automatically of any state changes, usually by calling one of
  > their methods.

  The observer pattern instantiates a **one-to-many** relationship between the
  subject and its observers: when one object updates, it notifies many other
  objects that it has been updated.

  This is another design pattern that is useful when implementing a global state.
  When the subject updates its subjects must follow suit and adapt to its changes.
  Here the subject is the instrument for maintaining the global state.

  ## Subject class

  This class maintains a list of observers that will be notified when it is
  updated. It should have the following attributes:

  - array of existing observers
  - an `addObserver` method which pushes an observer onto the observers array
  - a `removeObserver` method that does the opposite
  - a `notify` method that broadcasts to the observers that a change has happened

  ## Observer class

  Observers must implement an `update` method that will be called by the subject's
  `notify` method.

  ## Example

  ```js
  class Subject {
    observers = [];

    getCurrentTime() {
      var d = new Date();
      return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`;
    }

    addObserver(...observer) {
      for (const o of observer) {
        this.observers.push(o);
      }
    }
    removeObserver(observer) {
      const match = this.observers.findIndex((element) => element === observer);
      this.observers.splice(match, 1);
    }
    notify() {
      for (const o of this.observers) {
        o.update(`I was updated at ${this.getCurrentTime()}`);
      }
    }
  }

  class ObserverA {
    state = "I am observer A";
    update(newState) {
      this.state = newState;
    }
  }

  class ObserverB {
    state = "I am observer B";

    update(newState) {
      this.state = newState;
    }
  }

  let subjectInstance = new Subject();
  let obsAInstance = new ObserverA();
  let obsBInstance = new ObserverB();

  subjectInstance.addObserver(obsAInstance, obsBInstance);

  subjectInstance.notify();
  console.log(obsBInstance.state);
  ```

raw_content:
  ---
  tags:
    - OOP
    - design-patterns
  ---

  # Observer pattern

  The Observer design pattern is also known as the 'publish/subscribe' pattern.

  > The observer pattern is a software design pattern in which an object, called
  > the subject, maintains a list of its dependents, called observers, and
  > notifies them automatically of any state changes, usually by calling one of
  > their methods.

  The observer pattern instantiates a **one-to-many** relationship between the
  subject and its observers: when one object updates, it notifies many other
  objects that it has been updated.

  This is another design pattern that is useful when implementing a global state.
  When the subject updates its subjects must follow suit and adapt to its changes.
  Here the subject is the instrument for maintaining the global state.

  ## Subject class

  This class maintains a list of observers that will be notified when it is
  updated. It should have the following attributes:

  - array of existing observers
  - an `addObserver` method which pushes an observer onto the observers array
  - a `removeObserver` method that does the opposite
  - a `notify` method that broadcasts to the observers that a change has happened

  ## Observer class

  Observers must implement an `update` method that will be called by the subject's
  `notify` method.

  ## Example

  ```js
  class Subject {
    observers = [];

    getCurrentTime() {
      var d = new Date();
      return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`;
    }

    addObserver(...observer) {
      for (const o of observer) {
        this.observers.push(o);
      }
    }
    removeObserver(observer) {
      const match = this.observers.findIndex((element) => element === observer);
      this.observers.splice(match, 1);
    }
    notify() {
      for (const o of this.observers) {
        o.update(`I was updated at ${this.getCurrentTime()}`);
      }
    }
  }

  class ObserverA {
    state = "I am observer A";
    update(newState) {
      this.state = newState;
    }
  }

  class ObserverB {
    state = "I am observer B";

    update(newState) {
      this.state = newState;
    }
  }

  let subjectInstance = new Subject();
  let obsAInstance = new ObserverA();
  let obsBInstance = new ObserverB();

  subjectInstance.addObserver(obsAInstance, obsBInstance);

  subjectInstance.notify();
  console.log(obsBInstance.state);
  ```


path: Ohms_Law.md
sortable_path: Ohms_Law.md
title: Ohm's Law
checksum: d8bb6ce94a3a050e6f2494369e3a8fb2ae635a558fcf249321dd62a480ad4c31
created: 2024-10-22 16:52:58.090672771+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["physics","electricity"]}
lead:
  The relationship between
  [current](Current.md),
  [voltage](Voltage.md), and
  [resistance](Resistance.md) is
  defined by Ohm's Law:

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

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

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

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

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

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

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

  # Ohm's Law

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

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

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

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

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

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


path: OpenSearch.md
sortable_path: OpenSearch.md
title: OpenSearch
lead: ## Background
checksum: d9fbc072965e3e5b5484e8077a808c28dc8740b7014912eda50b714a9ec80193
created: 2024-10-22 16:52:58.10962675+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["AWS"]}
body:
  ## Background

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

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

  ## Key concepts

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

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

  ### Create domain

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

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

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

  #### Clusters and nodes

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

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

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

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

  ### Define index and mappings

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

  Our index will store each webpage as a document.

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

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

  The mapping will be utilised in the following scenarios:

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

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

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

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

  ### Querying and searching

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

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

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

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

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

  Example of the data returned:

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

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

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

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

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

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

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

  ### Query by date ranges

  Find pages published after a certain date:

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

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

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

  # OpenSearch

  ## Background

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

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

  ## Key concepts

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

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

  ### Create domain

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

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

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

  #### Clusters and nodes

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

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

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

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

  ### Define index and mappings

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

  Our index will store each webpage as a document.

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

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

  The mapping will be utilised in the following scenarios:

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

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

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

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

  ### Querying and searching

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

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

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

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

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

  Example of the data returned:

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

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

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

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

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

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

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

  ### Query by date ranges

  Find pages published after a certain date:

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

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


path: Operating_system_API.md
sortable_path: Operating_system_API.md
title: Operating system API
checksum: 7aeb44d375bb920e23b475fc0948194c841f603bdf7371ea17aa577bcf8e1d13
created: 2024-10-22 16:52:58.114945334+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"created":"Wednesday, July 17, 2024","tags":["operating-systems"]}
lead:
  A user can interact with the operating system either via the GUI or the
  [shell](Intro_to_the_Unix_shell.md). (Both ultimately access the OS via the
  shell since the UI is an abstraction layer of the shell.)

body:
  A user can interact with the operating system either via the GUI or the
  [shell](Intro_to_the_Unix_shell.md). (Both ultimately access the OS via the
  shell since the UI is an abstraction layer of the shell.)

  When _programs_ interact with the operating system they use the **operating
  system's API** directly. The GUI and shell also invoke the OS API but the access
  is mediated.

  Every OS has an API. This specification details how a program should interact
  with the OS, exposing functions, properties and data types.

  Whether using the GUI or a terminal emulator, the shell translates the user's
  commands into API calls. The API the invokes internal operating system code to
  perform the action.

  ![OS API diagram](../img/OS-api.svg)

  ## Example: opening a file

  A user can use a file explorer and the mouse to open a file. Or they can open
  the file by invoking it from the terminal.

  A running application doesn't have to do this. If it's remit includes opening
  files, it can do so by calling the OS API.

  On a Unix-like system the applicaton would use the `open` API function to open
  the file:

  ```
  open("foo.txt", 0_WRONLY|0_CREAT)
  ```

  This command makes the action write-only and creates the file because it does
  not yet exist. When the user opens a file in their File Explorer, the
  application translates their graphical actions into this API call.

  ## Different OSs have different APIs

  Unix-like and Linux operating systems use variations on the **Portable Operating
  System Interface** (POSIX) standard. This defines the OS API and also the rules
  for the shell's behaviour and its included utilities.

  Variations on this include _Cocoa_, macOS's API and Android's _Android Platform_
  API.

  Windows has its own API called _The Windows API_. The original version was
  16-bit called _Win16_, then when it moved to 32-bits it became _Win32_. When it
  moved to an x86 [instruction_set_architecture](Instruction_set_architectures.md)
  it became _Win64_. Starting with Windows 10, it introduced the _Universal
  Windows Platform_ which aims to make app development consistent accross
  different devices that run Windows.

raw_content:
  ---
  tags: [operating-systems]
  created: Wednesday, July 17, 2024
  ---

  # Operating system API

  A user can interact with the operating system either via the GUI or the
  [shell](Intro_to_the_Unix_shell.md). (Both ultimately access the OS via the
  shell since the UI is an abstraction layer of the shell.)

  When _programs_ interact with the operating system they use the **operating
  system's API** directly. The GUI and shell also invoke the OS API but the access
  is mediated.

  Every OS has an API. This specification details how a program should interact
  with the OS, exposing functions, properties and data types.

  Whether using the GUI or a terminal emulator, the shell translates the user's
  commands into API calls. The API the invokes internal operating system code to
  perform the action.

  ![OS API diagram](../img/OS-api.svg)

  ## Example: opening a file

  A user can use a file explorer and the mouse to open a file. Or they can open
  the file by invoking it from the terminal.

  A running application doesn't have to do this. If it's remit includes opening
  files, it can do so by calling the OS API.

  On a Unix-like system the applicaton would use the `open` API function to open
  the file:

  ```
  open("foo.txt", 0_WRONLY|0_CREAT)
  ```

  This command makes the action write-only and creates the file because it does
  not yet exist. When the user opens a file in their File Explorer, the
  application translates their graphical actions into this API call.

  ## Different OSs have different APIs

  Unix-like and Linux operating systems use variations on the **Portable Operating
  System Interface** (POSIX) standard. This defines the OS API and also the rules
  for the shell's behaviour and its included utilities.

  Variations on this include _Cocoa_, macOS's API and Android's _Android Platform_
  API.

  Windows has its own API called _The Windows API_. The original version was
  16-bit called _Win16_, then when it moved to 32-bits it became _Win32_. When it
  moved to an x86 [instruction_set_architecture](Instruction_set_architectures.md)
  it became _Win64_. Starting with Windows 10, it introduced the _Universal
  Windows Platform_ which aims to make app development consistent accross
  different devices that run Windows.


path: Order_of_operations.md
sortable_path: Order_of_operations.md
title: Order of operations
checksum: fc78c76d7c349997d2bcbd5869fe79de661b6b4d428894d5b5f8dbd5272e9dfa
created: 2024-10-22 16:52:58.127256435+00:00
modified: 2024-10-18 18:18:57.06868009+00:00
metadata: {"tags":["prealgebra"]}
lead:
  1. Evaluate expressions in **parentheses**
  1. Evaluate **exponents**
  1. Evaluate **multiplications and divisions** from left to right in the order
     that they appear
  1. Evaluate **additions and subtractions** from left to right in the order that
     they appear.

body:
  1. Evaluate expressions in **parentheses**
  1. Evaluate **exponents**
  1. Evaluate **multiplications and divisions** from left to right in the order
     that they appear
  1. Evaluate **additions and subtractions** from left to right in the order that
     they appear.

  In the absence of grouping symbols, addition holds no precedence over
  subtraction and vice versa.

  ```
  15 - 8 + 4 = 7 + 4
  					= 11
  ```

  ```
  15 - 8 + 4 = 15 - 12
  					 = 3
  ```

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

  # Order of operations

  1. Evaluate expressions in **parentheses**
  1. Evaluate **exponents**
  1. Evaluate **multiplications and divisions** from left to right in the order
     that they appear
  1. Evaluate **additions and subtractions** from left to right in the order that
     they appear.

  In the absence of grouping symbols, addition holds no precedence over
  subtraction and vice versa.

  ```
  15 - 8 + 4 = 7 + 4
  					= 11
  ```

  ```
  15 - 8 + 4 = 15 - 12
  					 = 3
  ```


path: Package_management_in_NodeJS.md
sortable_path: Package_management_in_NodeJS.md
title: Package management
lead: ## List installed packages
checksum: a4752920727fecb5b8ce97d7572b92652a86d679349fb8b71c6d9695790bc888
created: 2024-10-22 16:52:58.132426146+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["node-js"]}
body:
  ## List installed packages

  ```bash
  npm list
  ```

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

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

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

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

  ## View outdated modules

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

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

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

  ## Updating

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

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

  # Package management

  ## List installed packages

  ```bash
  npm list
  ```

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

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

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

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

  ## View outdated modules

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

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

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

  ## Updating

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


path: Pacman.md
sortable_path: Pacman.md
title: Pacman
lead: ## List all installed packages
checksum: 04aeff0db5edcee02210da9ca4b1e812e15f973f4e6b9b0c2bf896b737105c56
created: 2024-10-22 16:52:58.147092875+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["Linux","procedural","arch-linux"]}
body:
  ## List all installed packages

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

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

  ```
  pacman -Rcns
  ```

raw_content:
  ---
  tags:
    - Linux
    - procedural
    - arch-linux
  ---

  # Pacman

  ## List all installed packages

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

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

  ```
  pacman -Rcns
  ```


path: Passing_arguments_and_options_to_Bash_scripts.md
sortable_path: Passing_arguments_and_options_to_Bash_scripts.md
title: Passing arguments and options to Bash scripts
lead: ## Relation between commands and programs
checksum: 6556e370417eac93215b75f6ced2cd075840bb80b8cb644530db26e18760bae8
created: 2024-10-22 16:52:58.152434293+00:00
modified: 2024-10-18 17:55:56.289060649+00:00
metadata: {"tags":["shell"]}
body:
  ## Relation between commands and programs

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

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

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

  ## Passing arguments

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

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

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

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

  ```bash
  #!/bin/bash

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

  This outputs:

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

  Key points:

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

  ## Passing options

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

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

  We can handle an option-based input like:

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

  With the following construct:

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

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

  Which returns:

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

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

  ### The role of the colons

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

  This version demonstrates a more exhaustive use case:

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

  ```

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

  # Passing arguments and options to Bash scripts

  ## Relation between commands and programs

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

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

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

  ## Passing arguments

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

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

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

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

  ```bash
  #!/bin/bash

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

  This outputs:

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

  Key points:

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

  ## Passing options

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

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

  We can handle an option-based input like:

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

  With the following construct:

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

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

  Which returns:

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

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

  ### The role of the colons

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

  This version demonstrates a more exhaustive use case:

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

  ```


path: Passing_arguments_to_Python_scripts.md
sortable_path: Passing_arguments_to_Python_scripts.md
title: Passing arguments to Python scripts
lead:
  `sys.argv` is a list that contains the command-line arguments passed to a Python
  scripts.

checksum: 8b5c6497c1b17aaf8a5ad1d2d7f86edf63f3825229136af7133af23238556c9a
created: 2024-10-22 16:52:58.16085901+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Wednesday, June 19, 2024","id":"44li","tags":["python"]}
body:
  `sys.argv` is a list that contains the command-line arguments passed to a Python
  scripts.

  - `sys.argv[0]` = the name of script
  - `sys.argv[1]` = the first argument
  - `sys.argv[2]` = the second argument, and so on

  Example invocation:

  ```sh
  python3 ./my_script.py argument_one argument_two

  ```

  ```python
  import sys

  print(sys.argv[0])
  print(sys.arg)
  print(sys.argv[1])

  # my_script.py
  # ['my_script.py', 'argyment_one', 'argument_two']
  # argument_one

  ```

raw_content:
  ---
  id: 44li
  tags: [python]
  created: Wednesday, June 19, 2024
  ---

  # Passing arguments to Python scripts

  `sys.argv` is a list that contains the command-line arguments passed to a Python
  scripts.

  - `sys.argv[0]` = the name of script
  - `sys.argv[1]` = the first argument
  - `sys.argv[2]` = the second argument, and so on

  Example invocation:

  ```sh
  python3 ./my_script.py argument_one argument_two

  ```

  ```python
  import sys

  print(sys.argv[0])
  print(sys.arg)
  print(sys.argv[1])

  # my_script.py
  # ['my_script.py', 'argyment_one', 'argument_two']
  # argument_one

  ```


path: Peer_to_peer_network.md
sortable_path: Peer_to_peer_network.md
title: Peer to peer network
lead:
  A decentralised network model where each participant (peer) acts as both a
  client and a server.

checksum: bb1364bf5d9ed4a089d9697585e4832a7907e2142a23af856133de69e365e9e9
created: 2024-10-22 16:52:58.16517121+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"created":"Friday, August 09, 2024","tags":["networks"]}
body:
  A decentralised network model where each participant (peer) acts as both a
  client and a server.

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

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

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

  ## Benefits

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

  ## Drawbacks

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

raw_content:
  ---
  tags: [networks]
  created: Friday, August 09, 2024
  ---

  # Peer to peer network

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

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

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

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

  ## Benefits

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

  ## Drawbacks

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


path: Ports_in_NodeJS.md
sortable_path: Ports_in_NodeJS.md
title: Ports
checksum: c9975673e974869e0d02f1f89f50d66c63960e6cdd9b0af1d6d5912241e71bb3
created: 2024-10-22 16:52:58.176462358+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["node-js"]}
lead:
  When working in development we are able to specify the specific port from which
  we want top serve our application. In production, we do not always have this
  control: the port will most likely be set by the provider of the server
  environment.

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

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

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

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

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

  # Ports

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

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

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

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


path: Practical_walkthrough_Lambda_creation_within_AWS.md
sortable_path: Practical_walkthrough_Lambda_creation_within_AWS.md
title: Practical walkthrough of creating a Lambda function via the AWS Management Console
lead: ## Basic set-up
checksum: 8aaa595a4ee06aa4eaf98a9d65d0034ff5b0f795fe36d42fe503ee3453f7c696
created: 2024-10-22 16:52:58.187884267+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"tags":["AWS","aws-lambda","node-js"]}
body:
  ## Basic set-up

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

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

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

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

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

  ## Adding a trigger

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

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

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

  Now we see this step displayed in the dashboard:

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

  With the endpoint and other settings displayed:

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

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

  ## Handling parameters

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

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

    let message = "Hello Lambda";

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

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

    }
  };
  ```

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

  We get `Hello Thomas` as output.

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

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

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

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

  ## Basic set-up

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

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

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

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

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

  ## Adding a trigger

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

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

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

  Now we see this step displayed in the dashboard:

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

  With the endpoint and other settings displayed:

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

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

  ## Handling parameters

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

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

    let message = "Hello Lambda";

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

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

    }
  };
  ```

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

  We get `Hello Thomas` as output.

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

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


path: Prefixes_for_units_of_electrical_measurement.md
sortable_path: Prefixes_for_units_of_electrical_measurement.md
title: Prefixes for unit of electrical measurement
checksum: 8862db3b8a39d32e027c6882099e701167c87d7d3d07d136fba4c0ad18720de3
created: 2024-10-22 16:52:58.201338039+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["physics","electricity","exponents"]}
lead:
  In electronics we are often dealing with units that are very large or very
  small, thus we rely on [exponents](Exponents.md) for formal
  expression.

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

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

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

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

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

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

  # Prefixes for unit of electrical measurement

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

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

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

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

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


path: Prime_factorization.md
sortable_path: Prime_factorization.md
title: Prime factorisation
checksum: a0d7c79fc40d3516ced0e25bf401f8a8f8a001882682cd2b1101108d62b8400a
created: 2024-10-22 16:52:58.207895517+00:00
modified: 2024-10-18 18:19:08.46222599+00:00
metadata: {"tags":["prealgebra","number-theory"]}
lead:
  Prime factorisation is the activity of expressing a composite number as the
  unique product of [prime numbers](Primes%20and%20composites.md). There are two
  main approaches to this:

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

  - - factor\* trees
  - repeated division by two

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

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

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

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

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

  # Prime factorisation

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

  - - factor\* trees
  - repeated division by two

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

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

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

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


path: Primes_and_composites.md
sortable_path: Primes_and_composites.md
title: Prime and composite numbers
lead: Definition of a **prime number**:
checksum: dc753e7134e87d8c8702af7524489904121b6b8ef4884389166e2c482a0088df
created: 2024-10-22 16:52:58.219416429+00:00
modified: 2024-10-18 18:19:17.362392004+00:00
metadata: {"tags":["prealgebra","number-theory"]}
body:
  Definition of a **prime number**:

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

  Definition of a **composite number**:

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

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

  # Prime and composite numbers

  Definition of a **prime number**:

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

  Definition of a **composite number**:

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


path: Primitive_types.md
sortable_path: Primitive_types.md
title: Primitive types
checksum: 7e5afd3f7ab27ed61d7a12981598ff65f25a1a0bb6df6d01636b5b2332f9d00d
created: 2024-10-22 16:52:58.231299204+00:00
modified: 2024-10-18 17:55:56.289060649+00:00
metadata: {"tags":["typescript","data-types"]}
lead:
  The most basic type level is the one already present in JavaScript itself: the
  primitive data types: `boolean`, `string` and `number` . These are the types
  that would be returned from a `typeof` expression in ordinary JavaScript

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

  ## Type inference

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

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

  ## Arrays

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

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

  ## Object

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

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

  ## Array of (untyped) objects

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

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

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

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

  But better for reusability to do:

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

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

  ```

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

  # Primitive types

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

  ## Type inference

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

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

  ## Arrays

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

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

  ## Object

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

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

  ## Array of (untyped) objects

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

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

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

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

  But better for reusability to do:

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

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

  ```


path: Printing_values_in_C.md
sortable_path: Printing_values_in_C.md
title: Printing values in C
lead: ## To print a literal
checksum: ced1e80a73091c1f9c47ba46f368bc9999b9f74e507d4bc904524c2f85b2c28c
created: 2024-10-22 16:52:58.242627183+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"created":"Thursday, February 29, 2024 | 17:33","id":"3hcv0amc","tags":["C"]}
body:
  ## To print a literal

  ```c
  printf("hello world")
  ```

  ## To print a variable

  ```c
  int age = 25
  print("%d", age)

  ```

  The `%d` is an example of a [format specifier](./zk/format-specifiers-in-c.md).
  It is the decimal integer format specifier.

raw_content:
  ---
  id: 3hcv0amc
  tags:
    - C
  created: Thursday, February 29, 2024 | 17:33
  ---

  # Printing values in C

  ## To print a literal

  ```c
  printf("hello world")
  ```

  ## To print a variable

  ```c
  int age = 25
  print("%d", age)

  ```

  The `%d` is an example of a [format specifier](./zk/format-specifiers-in-c.md).
  It is the decimal integer format specifier.


path: Process_module_in_NodeJS.md
sortable_path: Process_module_in_NodeJS.md
title: The process module in Node.js
checksum: c0471abbd224662b086b5b3f40c8d67e46decb2adefb72bb979d0b92686a0b94
created: 2024-10-22 16:52:58.254775207+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["node-js"]}
lead:
  `process` is a core module and a global object accessible from anywhere in a
  Node.js application. It contains functionality that allows us to interact with
  information about the current process instance of Node.

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

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

  ## Managing runtime environments

  See
  [Managing Environments](Managing_environments_in_NodeJS.md).

  ## Accessing arguments: `process.argv`

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

  For instance if we run the following file:

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

  We get:

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

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

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

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

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

  Gives us:

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

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

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

  Say we ran a program that took in a username:

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

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

  ## Standard input and output

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

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

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

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

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

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

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

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

  So we add an exit clause:

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

  We can also execute functionality on the exit event:

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

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

  ### Additional useful methods

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

  ### `readline`

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

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

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

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

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

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

  # The `process` module in Node.js

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

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

  ## Managing runtime environments

  See
  [Managing Environments](Managing_environments_in_NodeJS.md).

  ## Accessing arguments: `process.argv`

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

  For instance if we run the following file:

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

  We get:

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

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

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

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

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

  Gives us:

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

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

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

  Say we ran a program that took in a username:

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

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

  ## Standard input and output

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

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

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

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

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

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

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

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

  So we add an exit clause:

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

  We can also execute functionality on the exit event:

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

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

  ### Additional useful methods

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

  ### `readline`

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

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

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

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

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


path: Processes.md
sortable_path: Processes.md
title: Processes
checksum: 2b331b124e4ae2014628e74cbe62db17966948066c36c6a255fecd473f58e76b
created: 2024-10-22 16:52:58.269252373+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"created":"Friday, June 21, 2024","id":"t70u","tags":["operating-systems"]}
lead:
  Programs are sequences of machine instructions stored in a file. However they do
  not work by themselves. Something needs to load the file's intructions into
  memory, direct the CPU to run the program and manage it during runtime. The OS
  does this via processes.

body:
  Programs are sequences of machine instructions stored in a file. However they do
  not work by themselves. Something needs to load the file's intructions into
  memory, direct the CPU to run the program and manage it during runtime. The OS
  does this via processes.

  A process **is a running instance of a given program**. It can be thought of as
  a container in which a program runs. This container includes:

  - a copy of the program code loaded into memory
  - a memory address
  - other information about the state of the process

  Other than the `init` process started by the kernel (PID1) (see
  ![systemd](systemd.md)), every process has a parent process that started it.
  This parent-child relationship creates a tree of processes.

  It is possible that a parent process will terminate before one of its child
  processes. In this instance the child becomes an orphan. When this occurs in
  #Linux, the orphan process is adopted by `init`.

  Below, I have used the `pstree` utility to list all the running processes on my
  machine hierarchically.

  ![diagram of `pstree` output](../img/ps-tree.png)

  Children are represented vertically and horizontally.

  ```
  ├─terminator─┬─zsh───tmux: client
  │            ├─zsh───pstree
  │            └─6*[{terminator}]

  ```

  For instance here, `terminator` is a child of `init`, as are `zsh` and `tmux`
  but they are also children of `terminator`.`pstree` is a child of `zsh` and
  therefore also a child (grandchild) of `terminator`.

  Each process has a unique identifier called a _process identifier_, a
  _processID_ or just _PID_.

  ## Related notes

  ![systemd](./systemd.md)

  ![ps](./ps.md)

  ![Monitoring processes and resources](Monitoring_processes_and_resources.md)

raw_content:
  ---
  id: t70u
  tags: [operating-systems]
  created: Friday, June 21, 2024
  ---

  # Processes

  Programs are sequences of machine instructions stored in a file. However they do
  not work by themselves. Something needs to load the file's intructions into
  memory, direct the CPU to run the program and manage it during runtime. The OS
  does this via processes.

  A process **is a running instance of a given program**. It can be thought of as
  a container in which a program runs. This container includes:

  - a copy of the program code loaded into memory
  - a memory address
  - other information about the state of the process

  Other than the `init` process started by the kernel (PID1) (see
  ![systemd](systemd.md)), every process has a parent process that started it.
  This parent-child relationship creates a tree of processes.

  It is possible that a parent process will terminate before one of its child
  processes. In this instance the child becomes an orphan. When this occurs in
  #Linux, the orphan process is adopted by `init`.

  Below, I have used the `pstree` utility to list all the running processes on my
  machine hierarchically.

  ![diagram of `pstree` output](../img/ps-tree.png)

  Children are represented vertically and horizontally.

  ```
  ├─terminator─┬─zsh───tmux: client
  │            ├─zsh───pstree
  │            └─6*[{terminator}]

  ```

  For instance here, `terminator` is a child of `init`, as are `zsh` and `tmux`
  but they are also children of `terminator`.`pstree` is a child of `zsh` and
  therefore also a child (grandchild) of `terminator`.

  Each process has a unique identifier called a _process identifier_, a
  _processID_ or just _PID_.

  ## Related notes

  ![systemd](./systemd.md)

  ![ps](./ps.md)

  ![Monitoring processes and resources](Monitoring_processes_and_resources.md)


path: Prop_types_in_React.md
sortable_path: Prop_types_in_React.md
title: Prop types
checksum: 727c77a483cc8cd4beceb26f9145e1f40aef386f77b3ac6c2f4b43d874e30039
created: 2024-10-22 16:52:58.275181372+00:00
modified: 2024-10-18 17:55:56.289060649+00:00
metadata: {"tags":["javascript","react","data-types"]}
lead:
  **The `prop-types` package allows us to introduce type-checking during the
  development runtime of a React application. With larger applications or those
  with complex data flows, this can help reduce errors and bugs during
  development. This is a bit like using TypeScript but on a more minimal level.**

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

  ## Install

  ```
  npm install prop-types
  ```

  ## Usage

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

  ## Examples

  Say we have a component with the following props:

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

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

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

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

  ## Additional checks

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

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

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

  // A function

  [propName]: PropTypes.func

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

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

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

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

  # Prop types

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

  ## Install

  ```
  npm install prop-types
  ```

  ## Usage

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

  ## Examples

  Say we have a component with the following props:

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

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

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

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

  ## Additional checks

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

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

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

  // A function

  [propName]: PropTypes.func

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

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

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


path: Proper_shebang_syntax.md
sortable_path: Proper_shebang_syntax.md
title: Proper shebang syntax
checksum: edcb7998f0254eab27ba5419de171e27c3a25fc8f6863e4021a0bbb4a4fbbece
created: 2024-10-22 16:52:58.279981413+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["shell"]}
lead:
  This is a more portable way of writing the shebang because the location of Bash
  on different systems can vary.

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

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

  Rather than:

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

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

  # Proper shebang syntax

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

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

  Rather than:

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


path: Props_in_React.md
sortable_path: Props_in_React.md
title: Props
lead: ## Types or interfaces?
checksum: 5932443b8d7abf3608aa338b3410754fc1976a0a2fc49a45a3a865dba90389b0
created: 2024-10-22 16:52:58.285102088+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["typescript","react"]}
body:
  ## Types or interfaces?

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

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

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

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

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

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

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

  ## How we type props

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

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

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

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

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

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

  ### Array of objects

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

  ### Functions

  ```tsx

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

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

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

  ### Other React components

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

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

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

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

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

  # Props

  ## Types or interfaces?

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

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

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

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

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

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

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

  ## How we type props

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

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

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

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

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

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

  ### Array of objects

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

  ### Functions

  ```tsx

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

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

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

  ### Other React components

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

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

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

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


path: Prototypical_inheritance.md
sortable_path: Prototypical_inheritance.md
title: Prototypical inheritance
lead: ## Object oriented basis of JavaScript and nomenclature
checksum: b332dfadb655c7db9d31679a6ca1dc695fef44a404f9abc92e05b34c43b517a7
created: 2024-10-22 16:52:58.290924445+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["javascript","OOP"]}
body:
  ## Object oriented basis of JavaScript and nomenclature

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

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

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

  ### Lack of classes in JS

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

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

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

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

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

  ### Example of a constructor function

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

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

  /* Then to create an object instance: */

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

  ## Prototypes

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

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

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

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

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

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

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

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

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

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

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

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

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

  ### Examples

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

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

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

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

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

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

  Band prototype in turn relies in turn on Object prototype: 

   Band.prototype._proto_=== Object.prototype

  */
  ```

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

  ### How the browser uses prototypes when interpreting code

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  Here is an example:

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

  /*

  Returns: 

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

  */
  ```

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

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

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

  ## But why bother using prototypes in your code?

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

  The reason is mainly to do with performance and optimisation

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

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

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

  Band.prototype.age = null;

  Slayer.age = 25;
  ```

  ## Further steps

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

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

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

  # Prototypical inheritance

  ## Object oriented basis of JavaScript and nomenclature

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

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

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

  ### Lack of classes in JS

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

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

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

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

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

  ### Example of a constructor function

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

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

  /* Then to create an object instance: */

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

  ## Prototypes

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

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

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

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

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

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

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

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

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

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

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

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

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

  ### Examples

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

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

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

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

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

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

  Band prototype in turn relies in turn on Object prototype: 

   Band.prototype._proto_=== Object.prototype

  */
  ```

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

  ### How the browser uses prototypes when interpreting code

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  Here is an example:

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

  /*

  Returns: 

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

  */
  ```

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

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

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

  ## But why bother using prototypes in your code?

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

  The reason is mainly to do with performance and optimisation

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

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

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

  Band.prototype.age = null;

  Slayer.age = 25;
  ```

  ## Further steps

  We are going to stop here for the time being since the primary aim of uncovering
  prototypes and understanding how they underly all objects and object methods in
  JS has been achieved.

  However it is important to note that there is more that you can do with
  prototypes. The main additional thing is using the prototypical basis of
  constructor functions (i.e pseudo-classes) to add and remove key value pairs in
  the resulting objects. This is useful when you want to create behaviour that is
  much more like classes in compiled OOP languages.


path: Push_buttons.md
sortable_path: Push_buttons.md
title: Push buttons
checksum: 04e804313c68988cb974b6293dd1807087288f983f73cecf701708e088b5522b
created: 2024-10-22 16:52:58.295816152+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"created":"Tuesday, June 25, 2024","id":"nsrv","tags":["electronics"]}
lead:
  Push buttons are push-to-make switches. This means that they are **on when they
  pressed and off when they are not pressed**. A classic example would be the
  switches on a keyboard.

body:
  Push buttons are push-to-make switches. This means that they are **on when they
  pressed and off when they are not pressed**. A classic example would be the
  switches on a keyboard.

  Push buttons have four legs that are connected in signal-in and signal-out
  pairs.

  To create a breakable circuit we would connect a signal-in cable to the top left
  at row 23 and a signal-out cable to the bottom-right at row 25.

  ![Push button legs diagram](../img/push-button-legs.png)

  _The correct use of a push button where the button breaks the circuit_

  ![](../img/correct_push_button.jpg)

  To override the switch functionality and just have the button work as a
  connector we would connect the signal-in to the row 23 input and the row 23
  output.

  _The push button being used as simple connector which does not break the
  circuit:_

  ![](../img/incorrect_push_button.jpg)

  ## Related notes

  https://projects.raspberrypi.org/en/projects/button-switch-scratch-pi/1

raw_content:
  ---
  id: nsrv
  tags: [electronics]
  created: Tuesday, June 25, 2024
  ---

  # Push buttons

  Push buttons are push-to-make switches. This means that they are **on when they
  pressed and off when they are not pressed**. A classic example would be the
  switches on a keyboard.

  Push buttons have four legs that are connected in signal-in and signal-out
  pairs.

  To create a breakable circuit we would connect a signal-in cable to the top left
  at row 23 and a signal-out cable to the bottom-right at row 25.

  ![Push button legs diagram](../img/push-button-legs.png)

  _The correct use of a push button where the button breaks the circuit_

  ![](../img/correct_push_button.jpg)

  To override the switch functionality and just have the button work as a
  connector we would connect the signal-in to the row 23 input and the row 23
  output.

  _The push button being used as simple connector which does not break the
  circuit:_

  ![](../img/incorrect_push_button.jpg)

  ## Related notes

  https://projects.raspberrypi.org/en/projects/button-switch-scratch-pi/1


path: Python_application_structure.md
sortable_path: Python_application_structure.md
title: Python application structure
lead: ## Directory layout
checksum: 49847157a3a69633258b7d00d93230bf9d910ce35d8d9c93ba462884d16c2071
created: 2024-10-22 16:52:58.301539216+00:00
modified: 2024-10-18 17:55:56.302394226+00:00
metadata: {"created":"Tuesday, August 27, 2024","tags":["python"]}
body:
  ## Directory layout

  ```
  src/
      cli.py OR app.py
      constants.py
      __init__.py
  tests/
  requirements.txt
  setup.py
  ```

  ## `requirements.txt`

  Dependencies used within the venv for the project, e.g:

  ```
  google-auth==1.35.0
  google-auth-httplib2==0.1.0
  google-auth-oauthlib==0.4.6
  google-api-python-client==2.26.1
  gspread==3.7.0
  requests==2.25.1
  oauth2client==4.1.3
  ```

  ## `setup.py`

  The declaration file for the application, equivalent to `package.json`, e.g:

  ```py
  from setuptools import setup, find_packages

  setup(
      name="eolas-db",
      version="0.1",
      packages=find_packages(where="src"),
      package_dir={"": "src"},
      install_requires=[
          # List your project dependencies here
      ],
      entry_points={
          "console_scripts": [
              "eolas-db=cli:main",
          ],
      },
  )
  ```

  The `entry_points` key is important. This is the first execution point of the
  application. Typically you would name your entry-point script as `app.py` or
  `cli.py` and then specify its `main` function.

  E.g. in `cli.py`:

  ```py
  def main():
      print('run the application')

  if __name__ == "__main__":
      main()

  ```

  ## `__init__.py`

  See
  [[Python_modules_and_imports#distinguishing-_modules_-from-_packages_]]|Python
  modules]]

raw_content:
  ---
  tags: [python]
  created: Tuesday, August 27, 2024
  ---

  # Python application structure

  ## Directory layout

  ```
  src/
      cli.py OR app.py
      constants.py
      __init__.py
  tests/
  requirements.txt
  setup.py
  ```

  ## `requirements.txt`

  Dependencies used within the venv for the project, e.g:

  ```
  google-auth==1.35.0
  google-auth-httplib2==0.1.0
  google-auth-oauthlib==0.4.6
  google-api-python-client==2.26.1
  gspread==3.7.0
  requests==2.25.1
  oauth2client==4.1.3
  ```

  ## `setup.py`

  The declaration file for the application, equivalent to `package.json`, e.g:

  ```py
  from setuptools import setup, find_packages

  setup(
      name="eolas-db",
      version="0.1",
      packages=find_packages(where="src"),
      package_dir={"": "src"},
      install_requires=[
          # List your project dependencies here
      ],
      entry_points={
          "console_scripts": [
              "eolas-db=cli:main",
          ],
      },
  )
  ```

  The `entry_points` key is important. This is the first execution point of the
  application. Typically you would name your entry-point script as `app.py` or
  `cli.py` and then specify its `main` function.

  E.g. in `cli.py`:

  ```py
  def main():
      print('run the application')

  if __name__ == "__main__":
      main()

  ```

  ## `__init__.py`

  See
  [[Python_modules_and_imports#distinguishing-_modules_-from-_packages_]]|Python
  modules]]


path: Python_data_types.md
sortable_path: Python_data_types.md
title: Python data-types
checksum: 87a8e9b94c5a6050161b68234964ee99022aef37f835f759d55a650977ba7b2f
created: 2024-10-22 16:52:58.318160227+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["python","data-types"]}
lead:
  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

body:
  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

  The core data-types are as follows:

  - [str](Strings_in_Python.md)
  - bool
  - float
  - double

  We can identify types using the built-in `type()` function:

  ```python
  # Integer number
  my_variable = 422
  print(my_variable)
  print(type(my_variable))
  # <class 'int'>

  # String type
  my_variable = 'Natalia'
  print(my_variable)
  print(type(my_variable))
  # <class 'str'>

  # Boolean type
  my_variable = True
  print(my_variable)
  print(type(my_variable))
  # <class 'bool'>
  ```

  ## Converting data-types

  For every data-type there is a corresponding converter method, e.g:

  ```python
  a_string = '32'
  print(f'a_string {a_string} is {type(a_string)}')
  an_int = int(a_string)

  print(f'an_int {a_string} is {type(an_int)}')
  a_float = float(a_string)

  print(f'a_float {a_string} is {type(a_float)}')
  another_string = str(42)

  print(f'another_string {a_string} is {type(another_string)}')
  ```

raw_content:
  ---
  tags: [python, data-types]
  ---

  # Python data-types

  - Python is dynamically typed rather than untyped. It updates the types on the
    fly as you are writing your code.
  - Type-hints in the editor like `-> str` mean "at the moment it is a string". It
    doesn't mean you can't redefine the value as something else.
  - Each data type in Python inherits off of a built-in class, similar to
    prototypes in JS

  The core data-types are as follows:

  - [str](Strings_in_Python.md)
  - bool
  - float
  - double

  We can identify types using the built-in `type()` function:

  ```python
  # Integer number
  my_variable = 422
  print(my_variable)
  print(type(my_variable))
  # <class 'int'>

  # String type
  my_variable = 'Natalia'
  print(my_variable)
  print(type(my_variable))
  # <class 'str'>

  # Boolean type
  my_variable = True
  print(my_variable)
  print(type(my_variable))
  # <class 'bool'>
  ```

  ## Converting data-types

  For every data-type there is a corresponding converter method, e.g:

  ```python
  a_string = '32'
  print(f'a_string {a_string} is {type(a_string)}')
  an_int = int(a_string)

  print(f'an_int {a_string} is {type(an_int)}')
  a_float = float(a_string)

  print(f'a_float {a_string} is {type(a_float)}')
  another_string = str(42)

  print(f'another_string {a_string} is {type(another_string)}')
  ```


path: Python_execution.md
sortable_path: Python_execution.md
title: Python execution
lead: For immediately executable scripts, we have to have a Python shebang at the top:
checksum: 30db233c5b46a73df2c5ab204f80b8f28ab8e94586db8ea06e7bcbe8cb0c090c
created: 2024-10-22 16:52:58.330128879+00:00
modified: 2024-10-18 17:55:56.292394043+00:00
metadata: {"tags":["python","data-types"]}
body:
  For immediately executable scripts, we have to have a Python shebang at the top:

  ```
  #! /usr/local/bin/python3
  ```

  With programs we can just run the `main` file with `python main.py`.

raw_content:
  ---
  tags: [python, data-types]
  ---

  # Python execution

  For immediately executable scripts, we have to have a Python shebang at the top:

  ```
  #! /usr/local/bin/python3
  ```

  With programs we can just run the `main` file with `python main.py`.


path: Python_interpreter.md
sortable_path: Python_interpreter.md
title: Python interpreter
lead: ## What is an implementation of a programming language?
checksum: 76b7b7c27f575074f2e906518a4155469c62525b955059dce6f9d22f5e9046eb
created: 2024-10-22 16:52:58.335283018+00:00
modified: 2024-10-18 17:55:56.295727437+00:00
metadata: {"tags":["python"]}
body:
  ## What is an implementation of a programming language?

  An implementation of Python:

  > means a program or environment which provides support for the execution of
  > programs written in the Python language

  As Python is interpreted, any implementation will perforce involve an
  interpreting language.

  There are three main implementations:

  - CPython
    - The default implementation, written in C
  - Jython
    - Python implemented by Java and running on the JVM
  - PyPy
    - A subset of Python which is faster due to machine code compilation

  ## CPython

  In the standard implementation, the language which interprets Python code is C.

  When Python runs in this implementation, code written in C converts it to
  bytecode (so-called because each instruction is
  [8-bits long](Binary_units_of_measurement.md)). This is a
  lower-level transliteration of Python is not meant to be understood by the CPU
  (since it is not binary) but rather to be run in the Python virtual machine
  which is equipped to understand bytecode. The Python Virtual Machine is
  therefore also known as "bytecode interpreter" or the CPython VM. The VM then
  converts bytecode into machine-executable code.

  The fact that Python does not compile to binary means that it can run on a
  greater variety of hardwares however it is slower than a language that compiles
  to machine code. PyPy is a solution for this because it is both interpreted and
  compiled to optimised machine code at run time.

  Where CPython is the interpreter, Python extensions can be written in C.

  ## PyPy

  PyPy is an alternative implementation to CPython. The main difference is that it
  uses a JIT-compiler and doesn't convert Python to the intermediary byte code. It
  is also written in Python itself, specifically RPython ('restricted Python').
  This is capable of converting Python directly to machine code without the
  CPython virtual machine.

  ## Jython

  Jython is an implementation of Python written in Java. Like CPython it converts
  Python to bytecode but this runs on the JVM. As it is written in Java, a Jython
  program can import and use any Java class.

  Where Jython is the interpreter, Python extension can be written in Java.

raw_content:
  ---
  tags: [python]
  ---

  # Python interpreter

  ## What is an implementation of a programming language?

  An implementation of Python:

  > means a program or environment which provides support for the execution of
  > programs written in the Python language

  As Python is interpreted, any implementation will perforce involve an
  interpreting language.

  There are three main implementations:

  - CPython
    - The default implementation, written in C
  - Jython
    - Python implemented by Java and running on the JVM
  - PyPy
    - A subset of Python which is faster due to machine code compilation

  ## CPython

  In the standard implementation, the language which interprets Python code is C.

  When Python runs in this implementation, code written in C converts it to
  bytecode (so-called because each instruction is
  [8-bits long](Binary_units_of_measurement.md)). This is a
  lower-level transliteration of Python is not meant to be understood by the CPU
  (since it is not binary) but rather to be run in the Python virtual machine
  which is equipped to understand bytecode. The Python Virtual Machine is
  therefore also known as "bytecode interpreter" or the CPython VM. The VM then
  converts bytecode into machine-executable code.

  The fact that Python does not compile to binary means that it can run on a
  greater variety of hardwares however it is slower than a language that compiles
  to machine code. PyPy is a solution for this because it is both interpreted and
  compiled to optimised machine code at run time.

  Where CPython is the interpreter, Python extensions can be written in C.

  ## PyPy

  PyPy is an alternative implementation to CPython. The main difference is that it
  uses a JIT-compiler and doesn't convert Python to the intermediary byte code. It
  is also written in Python itself, specifically RPython ('restricted Python').
  This is capable of converting Python directly to machine code without the
  CPython virtual machine.

  ## Jython

  Jython is an implementation of Python written in Java. Like CPython it converts
  Python to bytecode but this runs on the JVM. As it is written in Java, a Jython
  program can import and use any Java class.

  Where Jython is the interpreter, Python extension can be written in Java.


path: Python_modules_and_imports.md
sortable_path: Python_modules_and_imports.md
title: Python modules
lead: ## Distinguishing _modules_ from _packages_
checksum: c8d45e1dabc5ec3c2d533fd819b72a8b38b47d7f12b3614dc0e4c5e3835581d2
created: 2024-10-22 16:52:58.34460229+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["python","OOP"]}
body:
  ## Distinguishing _modules_ from _packages_

  Modules and packages in Python are very similar to modules in Node.js: a
  combination of several pieces of functionality (often written in a mix of
  different syntactic styles) bundled together to be used as a unit.

  - A **module** is basically just a script - a single Python file that you can
    import using the `import` statement
  - A **package** is a _collection of modules_

  A package is a whole directory which has an `__init__.py` at its root which
  designates it as a package (this can be empty, but it is necessary to have this
  file for the interpreter to understand that the directory is a package).

  ## Creating modules

  ### Naming modules

  The name of a module is the name of its file, e.g. `utils.py` defines the module
  `utils`. When we import a module we do not need to specify the extension.

  ### Example module

  Here is an example of a module.

  ```py
  """utils module"""

  print('Hello I am the utils module')


  def printer(some_object):
      print('printer')
      print(some_object)
      print('done')


  class Shape:

      def __init__(self, id):
          self.id = id

      def __str__(self):
          return 'Shape - ' + self.id


  default_shape = Shape('square')


  def _special_function():
      print('Special function')

  ```

  ## Importing modules

  > Whether we are importing our own local module, a third-party module or a
  > built-in module native to Python, the syntax is the same.

  - If the module is in the same directory as the file you wish to import it into,
    you can just directly import with:
    ```py
    import utils
    utils.specialFunction
    shape = utils.Shape('circle')
    ```
  - If the module you want to import is in a subdirectory, you will need to make
    that subdirectory a package in order to be able to import from it. This means
    adding an `__init__.py`. Then you can use the following import syntax:
    ```py
    from subdir import utils
    ...
    ```

  ### Different import syntax

  - If you don't want to have to prepend the imported module's name when using it
    (e.g. `utils.specialFunction`). You can import like so:

    ```py
    from utils import *
    specialFunction()
    ```

  - By default an import makes everything in the module available, however you can
    choose to import only a subset. E.g.:
    ```py
    from utils import Shape
    #  or with an alias:
    from utils import Shape as lorem
    ```

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

  When you run a script (module) Python assigns the string `__main__` to the
  `__name__` attribute to the script that is being executed.

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

  When used with a module, `__main__` indicates code that should be run straight
  away when the given script file is run. You won't always want to execute
  everything in the module file on execution so you can put this stuff outside of
  `__main__`

  Typically you will only want immediate execution to happen when **the module is
  the entrypoint** to the program.

  We indicate this with `__main__` as follows:

  ```py
  if __name__ == "__main__":
      print("This runs only if the module is the main module")
  ```

  ### Usage in packages

  The only real difference with packages is that you can also define a
  `__main__.py` file in the root of the package directory.

  This functions in the same manner as `__main__` in an individual module however
  this time it is not the entry point for a single script but the entrypoint of
  the package as a whole.

  > When the package is run directly as a script, the code in `__main__.py` is
  > executed, just like it would be if it were a standalone script. This allows a
  > package to be run as a script, as well as letting it contain modules that can
  > be imported separately.

  You can of course still have individual entrypoints for the modules that
  comprise the package.

  ### Running the package as a package

  If you want to run the whole package at once, rather than individually importing
  the modules that belong to it. You can run the following from the command-line:

  ```
  python -m package_name
  ```

  With this, Python will try to locate the `__main__.py` file and execute it as
  though it were a standalone script.

  ### Using a `main()` function

  To ensure that certain code runs on initialisation we can define a special
  `main` function or class method that runs when the module or package is
  loaded.We would put the main set-up logic in `main` and coordinate the execution
  of the module or package through it.

  ```py
  def main():
      printer(default_shape)
      shape = Shape("circle")
      printer(shape)

  if __name__ == "__main__":
      main()
  ```

  ### Example

  ```py
  '''palindrome module'''

  def is_palindrome(inp):
      inp_list = list(inp)
      inp_list_len = len(inp_list)
      for i in range(inp_list_len):
          if inp_list[i] != inp_list[inp_list_len - 1 - i]:
              return False
      return True


  def main():
      palindrome_one = "soros"
      palindrome_two = "torot"
      not_palindrome = "chair"

      print(is_palindrome(palindrome_one))
      print(is_palindrome(palindrome_two))
      print(is_palindrome(not_palindrome))


  if __name__ == '__main__':
      main()
  ```

raw_content:
  ---
  tags: [python, OOP]
  ---

  # Python modules

  ## Distinguishing _modules_ from _packages_

  Modules and packages in Python are very similar to modules in Node.js: a
  combination of several pieces of functionality (often written in a mix of
  different syntactic styles) bundled together to be used as a unit.

  - A **module** is basically just a script - a single Python file that you can
    import using the `import` statement
  - A **package** is a _collection of modules_

  A package is a whole directory which has an `__init__.py` at its root which
  designates it as a package (this can be empty, but it is necessary to have this
  file for the interpreter to understand that the directory is a package).

  ## Creating modules

  ### Naming modules

  The name of a module is the name of its file, e.g. `utils.py` defines the module
  `utils`. When we import a module we do not need to specify the extension.

  ### Example module

  Here is an example of a module.

  ```py
  """utils module"""

  print('Hello I am the utils module')


  def printer(some_object):
      print('printer')
      print(some_object)
      print('done')


  class Shape:

      def __init__(self, id):
          self.id = id

      def __str__(self):
          return 'Shape - ' + self.id


  default_shape = Shape('square')


  def _special_function():
      print('Special function')

  ```

  ## Importing modules

  > Whether we are importing our own local module, a third-party module or a
  > built-in module native to Python, the syntax is the same.

  - If the module is in the same directory as the file you wish to import it into,
    you can just directly import with:
    ```py
    import utils
    utils.specialFunction
    shape = utils.Shape('circle')
    ```
  - If the module you want to import is in a subdirectory, you will need to make
    that subdirectory a package in order to be able to import from it. This means
    adding an `__init__.py`. Then you can use the following import syntax:
    ```py
    from subdir import utils
    ...
    ```

  ### Different import syntax

  - If you don't want to have to prepend the imported module's name when using it
    (e.g. `utils.specialFunction`). You can import like so:

    ```py
    from utils import *
    specialFunction()
    ```

  - By default an import makes everything in the module available, however you can
    choose to import only a subset. E.g.:
    ```py
    from utils import Shape
    #  or with an alias:
    from utils import Shape as lorem
    ```

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

  When you run a script (module) Python assigns the string `__main__` to the
  `__name__` attribute to the script that is being executed.

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

  When used with a module, `__main__` indicates code that should be run straight
  away when the given script file is run. You won't always want to execute
  everything in the module file on execution so you can put this stuff outside of
  `__main__`

  Typically you will only want immediate execution to happen when **the module is
  the entrypoint** to the program.

  We indicate this with `__main__` as follows:

  ```py
  if __name__ == "__main__":
      print("This runs only if the module is the main module")
  ```

  ### Usage in packages

  The only real difference with packages is that you can also define a
  `__main__.py` file in the root of the package directory.

  This functions in the same manner as `__main__` in an individual module however
  this time it is not the entry point for a single script but the entrypoint of
  the package as a whole.

  > When the package is run directly as a script, the code in `__main__.py` is
  > executed, just like it would be if it were a standalone script. This allows a
  > package to be run as a script, as well as letting it contain modules that can
  > be imported separately.

  You can of course still have individual entrypoints for the modules that
  comprise the package.

  ### Running the package as a package

  If you want to run the whole package at once, rather than individually importing
  the modules that belong to it. You can run the following from the command-line:

  ```
  python -m package_name
  ```

  With this, Python will try to locate the `__main__.py` file and execute it as
  though it were a standalone script.

  ### Using a `main()` function

  To ensure that certain code runs on initialisation we can define a special
  `main` function or class method that runs when the module or package is
  loaded.We would put the main set-up logic in `main` and coordinate the execution
  of the module or package through it.

  ```py
  def main():
      printer(default_shape)
      shape = Shape("circle")
      printer(shape)

  if __name__ == "__main__":
      main()
  ```

  ### Example

  ```py
  '''palindrome module'''

  def is_palindrome(inp):
      inp_list = list(inp)
      inp_list_len = len(inp_list)
      for i in range(inp_list_len):
          if inp_list[i] != inp_list[inp_list_len - 1 - i]:
              return False
      return True


  def main():
      palindrome_one = "soros"
      palindrome_two = "torot"
      not_palindrome = "chair"

      print(is_palindrome(palindrome_one))
      print(is_palindrome(palindrome_two))
      print(is_palindrome(not_palindrome))


  if __name__ == '__main__':
      main()
  ```


path: Python_package_management.md
sortable_path: Python_package_management.md
title: Package management
checksum: 8d33751ae6c257ae49886e5c708ebcc0595691303be95e90dc2af0e07d212900
created: 2024-10-22 16:52:58.349604845+00:00
modified: 2024-10-18 17:55:56.299060832+00:00
metadata: {"tags":["python","data-types"]}
lead:
  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

body:
  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

  - The alternative is the native `pip` but you have to create virtual
    environments (`venv`) to manage packages at different versions.

  To make use of virtual environments in `pip` you have to create the virtual
  environment before installing anything:

  ```
  python3 -m venv venv
  ```

  This will create a `venv` directory in your project that will manage the
  handling of modules.

  > This is especially important in ArchLinux since without a virtual environment
  > it will ask you to install packages with `pacman` which is annoying for local
  > packages.

  You then activate the environment with:

  ```
  source venv3/bin/activate
  ```

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

  The `requirements.txt` file is similar to the `package.json` in Node projects.

  Each line of the `requirements.txt`` file specifies a package that your project
  depends on and, optionally, the desired version of that package. When you share
  your project with others or move it between different environments (e.g., from
  development to production), this file makes it easy to set up your environment
  with the right dependencies.

  ### Example

  ```
  Flask==1.1.2
  requests>=2.24.0
  numpy~=1.19.2
  pandas
  ```

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM

raw_content:
  ---
  tags: [python, data-types]
  ---

  # Package management

  - You can use `conda` (the package manager that comes with `anaconda`). This
    makes it easier to work with conflicting package libraries (a bit like a
    package lock).

  - The alternative is the native `pip` but you have to create virtual
    environments (`venv`) to manage packages at different versions.

  To make use of virtual environments in `pip` you have to create the virtual
  environment before installing anything:

  ```
  python3 -m venv venv
  ```

  This will create a `venv` directory in your project that will manage the
  handling of modules.

  > This is especially important in ArchLinux since without a virtual environment
  > it will ask you to install packages with `pacman` which is annoying for local
  > packages.

  You then activate the environment with:

  ```
  source venv3/bin/activate
  ```

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

  The `requirements.txt` file is similar to the `package.json` in Node projects.

  Each line of the `requirements.txt`` file specifies a package that your project
  depends on and, optionally, the desired version of that package. When you share
  your project with others or move it between different environments (e.g., from
  development to production), this file makes it easy to set up your environment
  with the right dependencies.

  ### Example

  ```
  Flask==1.1.2
  requests>=2.24.0
  numpy~=1.19.2
  pandas
  ```

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM


path: Querying_a_Mongo_collection.md
sortable_path: Querying_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-10-22 16:52:58.354020341+00:00
modified: 2024-10-18 17:55:56.299060832+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);
  }
  ```


