# notes

path: zk/Memory_leaks.md
sortable_path: zkMemory_leaks.md
title: Memory leaks
checksum: de91673c097f4d7f55e77811dd63de01feca7a18e5d548d519cc64e454bbac61
created: 2024-03-30 09:03:20.234256158+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Messaging_services.md
sortable_path: zkMessaging_services.md
title: AWS Messaging services
lead: ## SQS
checksum: eb8a75e05ac26b869762b86506c063c553af24181b6b7f0d27f7d451127bc5b8
created: 2024-03-30 09:03:20.238576676+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Middleware.md
sortable_path: zkMiddleware.md
title: Middleware
lead: ## What is middleware?
checksum: 8c55b331edfc2ab894723dd644c4113e8451dffbe95b91a807411314b8788ea4
created: 2024-03-30 09:03:20.246689953+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","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.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:
    - backend
    - 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.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: zk/Mixed_and_improper_fractions.md
sortable_path: zkMixed_and_improper_fractions.md
title: Mixed and improper fractions
lead: ## Improper fractions
checksum: 591035861210f541355bffec2836d38c935d09f90152f5328479bf5fca7cd409
created: 2024-03-30 09:03:20.260272834+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Modelling_relationships.md
sortable_path: zkModelling_relationships.md
title: Modelling relationships between data
checksum: 6713111dd236946eda14607a5e75abad017463a5c127ed88e58e0d61a1c92462
created: 2024-03-30 09:03:20.275316826+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["mongo-db","node-js","mongoose"]}
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]
  ---

  # Modelling relationships between data

  So far we have taken the values of a document to be simple: the `author` value
  is just a string but what if `author` was itself another collection for instance
  a collection with the proprties `age` and `publications` and the author name,
  say `Tosh Gnomay` was a document in this collection? This means we would have an
  interaction between two collections. In this entry we will look at how to work
  with interrelated collections. This is equivalent to establishing
  [joins](10_Joins.md) in a relational database.

  There are two main approaches to modelling relationships between data:
  **normalisation** and **denormalisation**.

  ## Modelling relationships with normalisation: using references

  In the case of normalisation we use a UUID from one document to connect it to
  another document.

  Let's say that we have a course document as follows which is an instance of the
  `courses` collection:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "Tosh Gnomay"
  }
  ```

  And we have a document which is an instance of another type of collection called
  `authors`. One instance of it could be:

  ```js
  {
      _id: "de89w9",
      name: "Tosh Gnomay",
      courses: ["Java course", "C# course"]
  }
  ```

  Using normalisation, we would establish the relationship by using the value of
  the `_id` propety in the `courses` document as the value of the `name` property
  in the `authors` document. We would rewrite the `courses` document like so:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: "de89w9"
  }
  ```

  ## Modelling relationships with denormalisation: embedding

  With denormalisation we achieve the same outcome but instead of using a
  reference we embed one value in another:

  ```js
  {
      _id: "ceds89e"
      name: "Java course",
      author: {
          name: "Tosh Gnomay",
          courses: ["Java course", "C# course"]
      }
  }
  ```

  ## Tradeoffs: which approach to use?

  There are drawbacks and benefits with each approach.

  - One benefit of normalisation is consistency. Because we are using the UUID and
    referencing it in another document, if we make a change to the values in the
    source document, it will automatically apply to all documents that reference
    it. We make a change in one place and it is reflected everywhere.

  - Conversely, a drawback of denormalisation is that it invites inconsistency
    between documents. Embedded values can easily go out of sync with their usage
    elsewhere as you don't have a direct reference correspondence.

  - On the other hand a drawback of normalisation is performance when querying.
    Any time you have a document that references another document than this
    document also has to be retrieved. Therefore for every query you are returning
    two documents. As denormalised references embed the second document, only one
    document is being returned on each query.


path: zk/Module_pattern.md
sortable_path: zkModule_pattern.md
title: Module pattern
lead: > Come back and compare this with learning from Node.js
checksum: f4959dd608fbcc87ccb71faa82ff8328afae0c2dab725672ea3b929835d50d48
created: 2024-03-30 09:03:20.283471991+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["OOP"]}
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]
  ---

  # 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: zk/Module_wrapping_at_runtime.md
sortable_path: zkModule_wrapping_at_runtime.md
title: The Module Wrapper Function
checksum: 1d65dd6b463ff91da51641ae7913c4d5cda2c68decfed29b366259440dfca1e6
created: 2024-03-30 09:03:20.287849942+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","node-js"]}
lead:
  When Node runs each of our module files are wrapped within an
  immediately-invoked function expression that has the following parameters:

body:
  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.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:
    - backend
    - node-js
  ---

  ## 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.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: zk/Modules.md
sortable_path: zkModules.md
title: Modules
checksum: 1657ff53b1f2ee329550ff89b6d85f5531fb34dc98d7d058e6109741a7c8db9b
created: 2024-03-30 09:03:20.294999712+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","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:
    - backend
    - 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: zk/Monitoring_processes_and_resources.md
sortable_path: zkMonitoring_processes_and_resources.md
title: Monitoring processes and resources
lead: ## General purpose diagnostic programs (memory, CPU, I/O)
checksum: 5927681432a67e395e580d00005ab486d5748d878481b20094754cb6347bb8fc
created: 2024-03-30 09:03:20.303803846+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["systems-programming"]}
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.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.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.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]
  ---

  # 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.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.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.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: zk/Morgan.md
sortable_path: zkMorgan.md
title: Morgan
lead: Morgan is middleware that is used to log HTTP requests to the Express instance.
checksum: 9ee9777827666f2f18ed6ffadfd9bdec183d951c55be488ba0f769e306e6d46a
created: 2024-03-30 09:03:20.359592551+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","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:
    - backend
    - 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: zk/Motherboard.md
sortable_path: zkMotherboard.md
title: Motherboard
lead: <img src="../img/motherboard-pi.jpg" width="400px"/>
checksum: 5d932cc05bccdd6ec22615800a5469d379721246b1552c9a160c1342785c2580
created: 2024-03-30 09:03:20.364422156+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["motherboard"]}
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: [motherboard]
  ---

  # 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: zk/Multiple_pointers.md
sortable_path: zkMultiple_pointers.md
title: Multiple pointers
checksum: ea69be937de502f66ab336fe3481f7bcfbbb3aac8c5dff1a87a765fdf3b97192
created: 2024-03-30 09:03:20.37853018+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":[]}
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: []
  ---

  # 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: zk/Multiplexers_and_demultiplexers.md
sortable_path: zkMultiplexers_and_demultiplexers.md
title: Multiplexers (MUX) and demultiplexers (DMUX)
lead: ## Multiplexer
checksum: 0323d69672331653828e0e1eb7e963a330e2e4b67995bc169955b8bc65148eb7
created: 2024-03-30 09:03:20.382660339+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Multiplicative_identity.md
sortable_path: zkMultiplicative_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-03-30 09:03:20.386291903+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Multiplicative_property_of_negative_one.md
sortable_path: zkMultiplicative_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-03-30 09:03:20.390062084+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Multiplying_fractions.md
sortable_path: zkMultiplying_fractions.md
title: Multiplying fractions
checksum: e693fb7d5cd07d76626f4e31e791a7cbb8bbd2effeb8cfe3169c7f2999b58136
created: 2024-03-30 09:03:20.39289207+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Mutations_with_Apollo_Client.md
sortable_path: zkMutations_with_Apollo_Client.md
title: Mutations with Apollo Client
lead: Queries are read-only operations. Mutations are write-only operations.
checksum: 880323da395777e103a129f870f5a4fabfd04b3e50d72c3b26f72dac1248fab6
created: 2024-03-30 09:03:20.40307229+00:00
modified: 2024-03-27 10:45:52.503525368+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
  retrun 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
  retrun 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: zk/Naming_conventions.md
sortable_path: zkNaming_conventions.md
title: Python naming conventions
lead: ## Underscores
checksum: f491ff1235bf5bb1a424568b00d219bbb0760f8c2b82962ba863401322fbac87
created: 2024-03-30 09:03:20.408941584+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Natural_numbers.md
sortable_path: zkNatural_numbers.md
title: The set of natural numbers
lead: $$ \mathbb{N} = {1, 2, 3, ...} $$
checksum: e42ef90c0ecd54ecd903240e8eacb31b42de3577739ae5f5d31f5b0737ef78bc
created: 2024-03-30 09:03:20.412983069+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["prealgebra"]}
body:
  $$ \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
  ---

  ## 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: zk/Negation_Elimination.md
sortable_path: zkNegation_Elimination.md
title: Negation Elimination
checksum: dd3f9b5499b1e4738866be7beb8e9eec4f27019523378d455d22ea21a0491ef6
created: 2024-03-30 09:03:20.417294279+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":[]}
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: []
  ---

  # 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: zk/Negation_Introduction.md
sortable_path: zkNegation_Introduction.md
title: Negation Introduction
checksum: 7d50df30532449f25a68b7efbb9a1aac00ae85dea0a5c01e2214cff9bd609127
created: 2024-03-30 09:03:20.426980275+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":[]}
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: []
  ---

  # 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: zk/Negative_exponents.md
sortable_path: zkNegative_exponents.md
lead:
  ---
  tags: [algebra, exponents]
  ---

checksum: 83982af46d75ecee22726807728c9f8881c79e45e98165afb961368864727976
created: 2024-03-30 09:03:20.430766589+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["algebra","exponents"]}
body:
  ---
  tags: [algebra, 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.

raw_content:
  ---
  tags: [algebra, 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: zk/Network_requests_in_Python.md
sortable_path: zkNetwork_requests_in_Python.md
title: Making network requests in Python
checksum: 4ffab8245cfa9de9d1a3639e18abc360c7d52e235b96b33beced9b53c478b206
created: 2024-03-30 09:03:20.434913949+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["python","APIs"]}
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.

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

  ```py
  {
     "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:

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

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

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

  ```py
  {
     "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:

  ```py
  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: zk/Node_and_MySQL_db.md
sortable_path: zkNode_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: 80488d31a20c8a984ce248b8fd382b9d76c82e4311845c5cd321de2b2775bce0
created: 2024-03-30 09:03:20.446869632+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["docker","SQL","node-js"]}
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.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]
  ---

  # 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.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: zk/Nodemon.md
sortable_path: zkNodemon.md
title: Nodemon
checksum: 1f782eb2009bce48bf5c97ee01144ce9287dfe310feaf0f9fc83a6d421105c79
created: 2024-03-30 09:03:20.460814283+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","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:
    - backend
    - 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: zk/Non_null_assertion.md
sortable_path: zkNon_null_assertion.md
title: Non-null assertion
lead: Oftentimes you will encounter errors of the form:
checksum: 3afb6d654d3d9d9c24f9155a366976af6b70dc7f501848f73c2cb17e7c8e6455
created: 2024-03-30 09:03:20.465731403+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/None_in_Python.md
sortable_path: zkNone_in_Python.md
title: None in Python
checksum: 185fdbfe796eb95a3ec84eab881a101129a444faade8c2bc76b831840d9c8a1b
created: 2024-03-30 09:03:20.477447631+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Numbers_in_Python.md
sortable_path: zkNumbers_in_Python.md
title: Numbers in Python
lead: ## Distinguishing `int` and `float`
checksum: 7686d82f635d53fb6d4a45f128d97422a6636463c04c96174ff31bbcbd339c69
created: 2024-03-30 09:03:20.481907953+00:00
modified: 2024-03-27 10:45:52.503525368+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: zk/Object_language_and_meta_language.md
sortable_path: zkObject_language_and_meta_language.md
title: Object and metalanguages
checksum: 8859d768ead1f2512adef6946ede25496d7a5a43329254af17106f7f318b77b7
created: 2024-03-30 09:03:20.486105099+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["propositional-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]
  ---

  # 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: zk/Observer_pattern.md
sortable_path: zkObserver_pattern.md
title: Observer pattern
lead: The Observer design pattern is also known as the 'publish/subscribe' pattern.
checksum: 99dd7804cf299b0c66c3128ba2673501804614fac6c91b8a33f1c7ac721d8dc1
created: 2024-03-30 09:03:20.489374856+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["OOP"]}
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]
  ---

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

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

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

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

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

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

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

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

  # Ohm's Law

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

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

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

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

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

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


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

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

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

  ## Key concepts

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

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

  ### Create domain

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

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

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

  #### Clusters and nodes

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

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

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

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

  ### Define index and mappings

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

  Our index will store each webpage as a document.

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

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

  The mapping will be utilised in the following scenarios:

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

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

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

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

  ### Querying and searching

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

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

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

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

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

  Example of the data returned:

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

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

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

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

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

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

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

  ### Query by date ranges

  Find pages published after a certain date:

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

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

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

  # OpenSearch

  ## Background

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

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

  ## Key concepts

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

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

  ### Create domain

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

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

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

  #### Clusters and nodes

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

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

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

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

  ### Define index and mappings

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

  Our index will store each webpage as a document.

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

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

  The mapping will be utilised in the following scenarios:

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

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

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

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

  ### Querying and searching

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

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

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

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

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

  Example of the data returned:

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

  ## Search patterns

  Below are further examples of commonly used search patterns.

  ### Multiple conditions

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

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

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

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

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

  ### Query by date ranges

  Find pages published after a certain date:

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

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


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

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

  1. Evaluate expressions in **parentheses**
  1. Evaluate **exponents**
  1. Evaluate **multiplications and divisions** from left to right in the order
     that they appear
  1. Evaluate **additions and subtractions** from left to right in the order that
     they appear.

  In the absence of grouping symbols, addition holds no precedence over
  subtraction and vice versa.

  ```
  15 - 8 + 4 = 7 + 4
  					= 11
  ```

  ```
  15 - 8 + 4 = 15 - 12
  					 = 3
  ```

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

  1. Evaluate expressions in **parentheses**
  1. Evaluate **exponents**
  1. Evaluate **multiplications and divisions** from left to right in the order
     that they appear
  1. Evaluate **additions and subtractions** from left to right in the order that
     they appear.

  In the absence of grouping symbols, addition holds no precedence over
  subtraction and vice versa.

  ```
  15 - 8 + 4 = 7 + 4
  					= 11
  ```

  ```
  15 - 8 + 4 = 15 - 12
  					 = 3
  ```


path: zk/Package_management.md
sortable_path: zkPackage_management.md
title: Package management
lead: ## List installed packages
checksum: 844be79fe931e4132b9e8574944503996f70ea71851000532a67e85cc86c7745
created: 2024-03-30 09:03:20.520292932+00:00
modified: 2024-03-27 10:45:52.503525368+00:00
metadata: {"tags":["backend","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:
    - backend
    - node-js
  ---

  # Package management

  ## List installed packages

  ```bash
  npm list
  ```

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

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

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

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

  ## View outdated modules

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

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

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

  ## Updating

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


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

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

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

  ```
  pacman -Rcns
  ```

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

  # Pacman

  ## List all installed packages

  ```
  pacman -Qe
  ```

  ## List all packages installed by current user

  ```
  pacman -Qqe
  ```

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

  ```
  pacman -Rcns
  ```


path: zk/Partitions.md
sortable_path: zkPartitions.md
title: Disk partitions
checksum: e66c22eb08f5df8308b9781790ec6a90a2eb107166db72d77d400583c504a00c
created: 2024-03-30 09:03:20.535805754+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["disks"]}
lead:
  A disk is divided up into [partitions](Partitions.md)
  which are subsections of the overall disk. The kernel presents each partition as
  a [block device](Devices.md#Devices) as it would with an
  entire disk.

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

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

  ## Viewing current partitions

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

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

  ```bash
  $ lsblk

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

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

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

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

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

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

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

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

  - Boot partition (`/dev/nvme0n1p1`)
    - This takes up the smallest amount of space and exists in order to bootstrap
      the operating system: to load the kernel into memory when the machine
      starts. This is where your bootloader is stored and that will be accessed by
      the BIOS. In Linux this will be GRUB.
  - Root dir (`/dev/nvme0n1p2`)
    - This is the domain of the
      [superuser](User_Space.md#root-user-superuser). The part
      of the filesystem that you need sudo priveleges to access and where you
      manage users
  - Home dir (`/dev/nvme0n1p3`)
    - The domain of the user(s)

  ## Types of partition table

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

  #### Primary, extended and logical partitions

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

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

  In our example above:

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

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

  ## Creating a partition table

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

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

  ```
  $ fdisk -l

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

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

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

  #### 1. Unmount existing partitions

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

  #### 2. Deleting the existing partitions

  ```bash
  # Load the disk into fdisk
  $ sudo fdisk /dev/sda

  # Select delete and run for each partition
  Command (m for help): d
  Partition number (1,2, default 2): 1

  Partition 1 has been deleted.

  Command (m for help): d
  Selected partition 2
  Partition 2 has been deleted.

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

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

  # Check execution:
  $ lsblk
  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ```

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

  #### 3. Re-partition the disk

  We are going to create a GPT partition table

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

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

  # Just press enter here

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

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

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

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

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

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

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

  We can now confirm out new partitions:

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

  #### Naming a partition

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

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

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

raw_content:
  ---

  tags:
    - disks
  ---

  # Disk partitions

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

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

  ## Viewing current partitions

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

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

  ```bash
  $ lsblk

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

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

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

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

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

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

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

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

  - Boot partition (`/dev/nvme0n1p1`)
    - This takes up the smallest amount of space and exists in order to bootstrap
      the operating system: to load the kernel into memory when the machine
      starts. This is where your bootloader is stored and that will be accessed by
      the BIOS. In Linux this will be GRUB.
  - Root dir (`/dev/nvme0n1p2`)
    - This is the domain of the
      [superuser](User_Space.md#root-user-superuser). The part
      of the filesystem that you need sudo priveleges to access and where you
      manage users
  - Home dir (`/dev/nvme0n1p3`)
    - The domain of the user(s)

  ## Types of partition table

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

  #### Primary, extended and logical partitions

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

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

  In our example above:

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

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

  ## Creating a partition table

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

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

  ```
  $ fdisk -l

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

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

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

  #### 1. Unmount existing partitions

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

  #### 2. Deleting the existing partitions

  ```bash
  # Load the disk into fdisk
  $ sudo fdisk /dev/sda

  # Select delete and run for each partition
  Command (m for help): d
  Partition number (1,2, default 2): 1

  Partition 1 has been deleted.

  Command (m for help): d
  Selected partition 2
  Partition 2 has been deleted.

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

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

  # Check execution:
  $ lsblk
  NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  sda           8:0    0 465.7G  0 disk
  ```

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

  #### 3. Re-partition the disk

  We are going to create a GPT partition table

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

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

  # Just press enter here

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

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

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

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

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

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

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

  We can now confirm out new partitions:

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

  #### Naming a partition

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

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

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


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

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

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

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

  ## Passing arguments

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

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

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

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

  ```bash
  #!/bin/bash

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

  This outputs:

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

  Key points:

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

  ## Passing options

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

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

  We can handle an option-based input like:

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

  With the following construct:

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

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

  Which returns:

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

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

  ### The role of the colons

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

  This version demonstrates a more exhaustive use case:

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

  ```

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

  # Passing arguments and options to Bash scripts

  ## Relation between commands and programs

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

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

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

  ## Passing arguments

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

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

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

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

  ```bash
  #!/bin/bash

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

  This outputs:

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

  Key points:

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

  ## Passing options

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

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

  We can handle an option-based input like:

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

  With the following construct:

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

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

  Which returns:

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

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

  ### The role of the colons

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

  This version demonstrates a more exhaustive use case:

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

  ```


path: zk/Ports.md
sortable_path: zkPorts.md
title: Ports
checksum: a07f52228dc9cd9fe647f505d605003e36a5d08edc08dfeee627de2ccc194b2f
created: 2024-03-30 09:03:20.5676326+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["backend","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:
    - backend
    - node-js
  ---

  # Ports

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

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

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

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


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

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

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

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

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

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

  ## Adding a trigger

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

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

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

  Now we see this step displayed in the dashboard:

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

  With the endpoint and other settings displayed:

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

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

  ## Handling parameters

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

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

    let message = "Hello Lambda";

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

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

    }
  };
  ```

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

  We get `Hello Thomas` as output.

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

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

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

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

  ## Basic set-up

  First we name the function and accept the defaults:

  ![](/img/lambda_func_one.png)

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

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

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

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

  ## Adding a trigger

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

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

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

  Now we see this step displayed in the dashboard:

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

  With the endpoint and other settings displayed:

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

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

  ## Handling parameters

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

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

    let message = "Hello Lambda";

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

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

    }
  };
  ```

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

  We get `Hello Thomas` as output.

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

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


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

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

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

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

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

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

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

  # Prefixes for unit of electrical measurement

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

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

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

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

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


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

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

  - - factor\* trees
  - repeated division by two

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

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

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

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

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

  ### Prime factorisation

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

  - - factor\* trees
  - repeated division by two

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

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

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

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


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

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

  Definition of a **composite number**:

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

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

  ## Prime and composite numbers

  Definition of a **prime number**:

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

  Definition of a **composite number**:

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


path: zk/Primitive_types.md
sortable_path: zkPrimitive_types.md
title: Primitive types
checksum: 4c22c8bf1e4f68eac9b2ac491f8a64a11a12fbbfa46fd0406a02a802d04a269c
created: 2024-03-30 09:03:20.62007709+00:00
modified: 2024-03-27 10:45:52.506858751+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.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.md).

  ## Array of (untyped) objects

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

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

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

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

  But better for reusability to do:

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

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

  ```


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

checksum: a858d422a2c60511512a28ed9bac6959e67c830b44a0da55b571326917c19bf5
created: 2024-03-30 09:03:20.629874277+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  `ps` allows us to control [user processes](The_Kernel.md)
  from the shell.

  The command in its most minimal application returns the following

  ```
    PID TTY       TIME     CMD
    2437 pts/2    00:00:01 zsh
    7112 pts/2    00:00:00 ps
  ```

  With the `-e` modifier we can list more processes:

  ```
   PID TTY          TIME CMD
        1 ?        00:00:05 systemd
        2 ?        00:00:00 kthreadd
        3 ?        00:00:00 rcu_gp
        4 ?        00:00:00 rcu_par_gp
        5 ?        00:00:00 netns
        7 ?        00:00:00 kworker/0:0H-events_highpri
        9 ?        00:00:00 mm_percpu_wq
       11 ?        00:00:00 rcu_tasks_kthread
       12 ?        00:00:00 rcu_tasks_rude_kthread
       13 ?        00:00:00 rcu_tasks_trace_kthread
       14 ?        00:00:08 ksoftirqd/0
       15 ?        00:03:20 rcu_preempt
       16 ?        00:00:00 rcub/0
       17 ?        00:00:00 migration/0
       18 ?        00:00:00 idle_inject/0
       20 ?        00:00:00 cpuhp/0
       21 ?        00:00:00 cpuhp/1
       22 ?        00:00:00 idle_inject/1
       23 ?        00:00:00 migration/1
  ```

  <dl>
  <dt>pid</dt>
  <dd>Process ID: every currently running process has a unique ID<dd>
  <dt>tty</dt>
  <dd>The terminal device where the process is running<dd>
  <dt>Time</dt>
  <dd>The amount of CPU time in minutes and seconds that the process has used so far. The total amount of time that the process has spent running instructions on the processor.<dd>
  <dt>cmd</dt>
  <dd>The command used to run the program. Note this can change during the running of the program.<dd>
  </dl>

  ## Modifiers

  <dl>
  <dt><code>ps x</code></dt>
  <dd>Show all running processes<dd>
  <dt><code>ps ax</code></dt>
  <dd>Show all processes not just the ones you, the current user, own<dd>
  <dt><code>ps u</code></dt>
  <dd>Show detailed info on processes<dd>
  <dt><code>ps w</code></dt>
  <dd>Show full command names<dd>
  </dl>

  ## Process termination

  The general schema is: `kill [pid]`. This allows for process clean-up. If this
  doesn't succeed you can force with `KILL [pid]` which will terminate the process
  immediately but is obviously more risky.

  We can also start/stop processes with modifiers on `kill`:

  - `kill -STOP pid`
  - `kill -CONT pid`

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

  # Processes (`ps`)

  `ps` allows us to control [user processes](The_Kernel.md)
  from the shell.

  The command in its most minimal application returns the following

  ```
    PID TTY       TIME     CMD
    2437 pts/2    00:00:01 zsh
    7112 pts/2    00:00:00 ps
  ```

  With the `-e` modifier we can list more processes:

  ```
   PID TTY          TIME CMD
        1 ?        00:00:05 systemd
        2 ?        00:00:00 kthreadd
        3 ?        00:00:00 rcu_gp
        4 ?        00:00:00 rcu_par_gp
        5 ?        00:00:00 netns
        7 ?        00:00:00 kworker/0:0H-events_highpri
        9 ?        00:00:00 mm_percpu_wq
       11 ?        00:00:00 rcu_tasks_kthread
       12 ?        00:00:00 rcu_tasks_rude_kthread
       13 ?        00:00:00 rcu_tasks_trace_kthread
       14 ?        00:00:08 ksoftirqd/0
       15 ?        00:03:20 rcu_preempt
       16 ?        00:00:00 rcub/0
       17 ?        00:00:00 migration/0
       18 ?        00:00:00 idle_inject/0
       20 ?        00:00:00 cpuhp/0
       21 ?        00:00:00 cpuhp/1
       22 ?        00:00:00 idle_inject/1
       23 ?        00:00:00 migration/1
  ```

  <dl>
  <dt>pid</dt>
  <dd>Process ID: every currently running process has a unique ID<dd>
  <dt>tty</dt>
  <dd>The terminal device where the process is running<dd>
  <dt>Time</dt>
  <dd>The amount of CPU time in minutes and seconds that the process has used so far. The total amount of time that the process has spent running instructions on the processor.<dd>
  <dt>cmd</dt>
  <dd>The command used to run the program. Note this can change during the running of the program.<dd>
  </dl>

  ## Modifiers

  <dl>
  <dt><code>ps x</code></dt>
  <dd>Show all running processes<dd>
  <dt><code>ps ax</code></dt>
  <dd>Show all processes not just the ones you, the current user, own<dd>
  <dt><code>ps u</code></dt>
  <dd>Show detailed info on processes<dd>
  <dt><code>ps w</code></dt>
  <dd>Show full command names<dd>
  </dl>

  ## Process termination

  The general schema is: `kill [pid]`. This allows for process clean-up. If this
  doesn't succeed you can force with `KILL [pid]` which will terminate the process
  immediately but is obviously more risky.

  We can also start/stop processes with modifiers on `kill`:

  - `kill -STOP pid`
  - `kill -CONT pid`


path: zk/Prop_types.md
sortable_path: zkProp_types.md
title: Prop types
checksum: 727c77a483cc8cd4beceb26f9145e1f40aef386f77b3ac6c2f4b43d874e30039
created: 2024-03-30 09:03:20.640858185+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","react","data-types"]}
lead:
  **The `prop-types` package allows us to introduce type-checking during the
  development runtime of a React application. With larger applications or those
  with complex data flows, this can help reduce errors and bugs during
  development. This is a bit like using TypeScript but on a more minimal level.**

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

  ## Install

  ```
  npm install prop-types
  ```

  ## Usage

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

  ## Examples

  Say we have a component with the following props:

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

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

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

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

  ## Additional checks

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

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

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

  // A function

  [propName]: PropTypes.func

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

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

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

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

  # Prop types

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

  ## Install

  ```
  npm install prop-types
  ```

  ## Usage

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

  ## Examples

  Say we have a component with the following props:

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

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

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

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

  ## Additional checks

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

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

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

  // A function

  [propName]: PropTypes.func

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

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

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


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

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

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

  Rather than:

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

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

  # Proper shebang syntax

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

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

  Rather than:

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


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

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

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

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

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

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

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

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

  ## How we type props

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

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

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

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

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

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

  ### Array of objects

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

  ### Functions

  ```tsx

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

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

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

  ### Other React components

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

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

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

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

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

  # Props

  ## Types or interfaces?

  They are mostly interchangeable but there are some specific differences

  ### Interfaces

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

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

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

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

    ```ts
    interface Window {
        }

    interface Window {
      ts: TypeScriptAPI;
    }
    ```

  ### Types

  You can create unions with types but not interfaces.

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

  ## How we type props

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

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

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

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

  ```

  Then in the parent:

  ```tsx

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

  <List props={people}>

  ```

  ## Common types for props

  ### Object with any number of properties

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

  ### Array of objects

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

  ### Functions

  ```tsx

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

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

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

  ### Other React components

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

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

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

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


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

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

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

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

  ### Lack of classes in JS

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

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

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

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

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

  ### Example of a constructor function

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

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

  /* Then to create an object instance: */

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

  ## Prototypes

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

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

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

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

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

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

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

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

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

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

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

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

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

  ### Examples

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

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

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

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

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

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

  Band prototype in turn relies in turn on Object prototype: 

   Band.prototype._proto_=== Object.prototype

  */
  ```

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

  ### How the browser uses prototypes when interpreting code

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  Here is an example:

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

  /*

  Returns: 

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

  */
  ```

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

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

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

  ## But why bother using prototypes in your code?

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

  The reason is mainly to do with performance and optimisation

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

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

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

  Band.prototype.age = null;

  Slayer.age = 25;
  ```

  ## Further steps

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

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

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

  # Prototypical inheritance

  ## Object oriented basis of JavaScript and nomenclature

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

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

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

  ### Lack of classes in JS

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

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

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

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

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

  ### Example of a constructor function

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

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

  /* Then to create an object instance: */

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

  ## Prototypes

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

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

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

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

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

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

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

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

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

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

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

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

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

  ### Examples

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

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

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

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

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

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

  Band prototype in turn relies in turn on Object prototype: 

   Band.prototype._proto_=== Object.prototype

  */
  ```

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

  ### How the browser uses prototypes when interpreting code

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  Here is an example:

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

  /*

  Returns: 

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

  */
  ```

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

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

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

  ## But why bother using prototypes in your code?

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

  The reason is mainly to do with performance and optimisation

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

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

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

  Band.prototype.age = null;

  Slayer.age = 25;
  ```

  ## Further steps

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

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


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

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

  The core data-types are as follows:

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

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

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

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

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

  ## Converting data-types

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

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

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

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

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

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

  # Python data-types

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

  The core data-types are as follows:

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

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

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

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

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

  ## Converting data-types

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

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

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

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

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


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

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

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

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

  # Python execution

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

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

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


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

  An implementation of Python:

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

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

  There are three main implementations:

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

  ## CPython

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

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

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

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

  ## PyPy

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

  ## Jython

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

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

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

  # Python interpreter

  ## What is an implementation of a programming language?

  An implementation of Python:

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

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

  There are three main implementations:

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

  ## CPython

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

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

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

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

  ## PyPy

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

  ## Jython

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

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


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

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

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

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

  ## Creating modules

  ### Naming modules

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

  ### Example module

  Here is an example of a module.

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

  print('Hello I am the utils module')


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


  class Shape:

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

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


  default_shape = Shape('square')


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

  ```

  ## Importing modules

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

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

  ### Different import syntax

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

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

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

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

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

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

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

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

  We indicate this with `__main__` as follows:

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

  ### Usage in packages

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

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

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

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

  ### Running the package as a package

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

  ```
  python -m package_name
  ```

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

  ### Using a `main()` function

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

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

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

  ### Example

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

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


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

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


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

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

  # Python modules

  ## Distinguishing _modules_ from _packages_

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

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

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

  ## Creating modules

  ### Naming modules

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

  ### Example module

  Here is an example of a module.

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

  print('Hello I am the utils module')


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


  class Shape:

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

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


  default_shape = Shape('square')


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

  ```

  ## Importing modules

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

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

  ### Different import syntax

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

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

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

  ## `__main__`

  The `__main__` attribute is important in Python.

  ### Usage in scripts/modules

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

  If you run the script as an import into another script, the `__name__` attribute
  of the imported module is set to the module name, not `__main__`. This is why,
  when we import we say `import [module_name]` and not `import __main__`.

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

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

  We indicate this with `__main__` as follows:

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

  ### Usage in packages

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

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

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

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

  ### Running the package as a package

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

  ```
  python -m package_name
  ```

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

  ### Using a `main()` function

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

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

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

  ### Example

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

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


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

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


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


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

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

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

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

  ```
  python3 -m venv venv
  ```

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

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

  You then activate the environment with:

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

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

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

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

  ### Example

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

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM

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

  # Package management

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

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

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

  ```
  python3 -m venv venv
  ```

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

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

  You then activate the environment with:

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

  Now you can install packages:

  ```
  pip [library_name]
  ```

  ## requirements.txt

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

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

  ### Example

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

  ### Generate requirements file

  ```
  pip freeze > requirements.txt

  ```

  ## Pypy

  - pypi.org is package registry like NPM


path: zk/Querying_a_collection.md
sortable_path: zkQuerying_a_collection.md
title: Query a Mongo collection with Mongoose
lead: We now have the following entries in our `courses` collection:
checksum: c525299cf5a601e0fe01d159613e1390c99ef6b90ccfb562fc7d9049f3f9d65d
created: 2024-03-30 09:03:20.691003814+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["mongo-db","node-js","mongoose"]}
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]
  ---

  # Query a Mongo collection with Mongoose

  We now have the following entries in our `courses` collection:

  ```js
  {
    name: 'Python Course',
    author: 'Terry Ogleton',
    tags: [ 'python', 'backend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d23"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  {
    name: 'Javascript Course',
    author: 'Tosh Gnomay',
    tags: [ 'js', 'frontend' ],
    isPublished: true,
    _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
    date: 2022-08-11T11:04:50.750Z,
    __v: 0
  }

  ```

  Now we will query the collection. This capability is provided via the Mongoose
  schema class we used to create the `Course`
  [model](Create_collections_and_documents_with_Mongoose.md#models).
  We have the following methods available to use from the schema:

  - `find`
  - `findById`
  - `findByIdAndRemove`
  - `findByIdAndUpdate`
  - `findOne`
  - `findOneAndUpdate`
  - `findOneAndRemove`
  - ...

  The various `find` methods return a value that is promisified.

  ## Return values with `find`

  ```js
  async function getCourses() {
    const courses = await Course.find();
    console.log(courses);
  }
  ```

  ## Filter values returned

  This will return all the published courses where Tosh Gnomay is the author:

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    });
    console.log(courses);
  }
  ```

  This time we will filter by the same author but we will add additional
  parameters to distinguish:

  - only the first ten entries (using `.limit(10)`)
  - sort ascending by name (using `.sort({name: 1}))` , to descend we would use
    `-1`)
  - only return the properties `name` and `tags` for the item in the collection
    (using `.select({name: 1, tags: 1})`)

  ```js
  async function getCourses() {
    const courses = await Course.find({
      author: "Tosh Gnomay",
      isPublished: true,
    })
      .limit(10)
      .sort({ name: 1 })
      .select({ name: 1, tags: 1 });
    console.log(courses);
  }
  ```

  This returns:

  ```js
  [
    {
      _id: new ObjectId("62f4f07a875cff48827b8731"),
      name: "Java Course",
      tags: ["java", "backend"],
    },
    {
      _id: new ObjectId("62f4e2527ac4aa2c30d41d24"),
      name: "Javascript Course",
      tags: ["js", "frontend"],
    },
  ];
  ```

  > Note that the UUID is always returned, whether we specify it or not.

  ## Querying with operators

  So far when filtering we have been doing so with reference to properties that
  exist on the document's model (`author`, `isPublished` etc) and we have applied
  tranformations on the data returned (sorting, limiting the number or matches
  etc.). However we can also apply **operators** within our queries. Operators
  allow us to perform computations on the data, for example: for a given numerical
  property on an object, return the objects for which this value is within a
  certain range.

  When we apply operators we use the `$` symbol before the operator and pass the
  operator function as an object.

  The schema:

  ```
  Model.find( { property: { $operator: conditions } } )
  ```

  ### Comparison operators

  The following comparison operators are available in MongoDB:

  | Operator | Function                  |
  | -------- | ------------------------- |
  | `eq`     | Equal to                  |
  | `ne`     | Not equal to              |
  | `gt`     | Greater than              |
  | `gte`    | Greater than or less than |
  | `lt`     | Less than                 |
  | `lte`    | Less than or equal to     |
  | `in`     | In                        |
  | `nin`    | Not in                    |

  We can employ these comparators within a `.find` filter. For example let's
  imagine that our `courses` instances have a property of `price`.

  To filter course prices that are greater than or equal to 10 and less than or
  equal to 29:

  ```js
  Course.find({ price: { $gte: 10, $lte: 20 } });
  ```

  To filter course prices that are either 10, 15 or 20:

  ```js
  Course.find({ price: { $in: [10, 15, 20] } });
  ```

  ### Logical operators

  When we apply logical operators, we do not apply the query within the main
  `find` method. We use a dedicated method that corresponds to the logical
  predicate.

  For example to query by logical
  [OR](Truth-functional_connectives.md#disjunction):

  ```js
  async function getCourses() {
    const courses = await Course.find().or([
      { author: "Tosh Gnomay" },
      { isPublished: true },
    ]);
    console.log(courses);
  }
  ```

  We write each disjunct as an object representing the conditions we are filtering
  for within an array that is passed to the `.or()` method.

  The same syntax applies for conjunction.

  ### Regular expressions

  When filtering by strings we can use Regex for greater power.

  Previously we filtered by the author name:

  ```js
  .find({author: "Tosh Gnomay"})
  ```

  To demonstrate regex we could filter by names beginning with `T`:

  ```js
  .find({author: /^T*/})
  ```

  ```js
  async function getCourses() {
    const courses = await Course.find()
      .or([{ author: "Tosh Gnomay" }, { isPublished: true }])
      .count();
    console.log(courses);
  }
  ```

  This will return a number.

  ### Pagination

  We previously used the `limit()` method to control how many matches we return
  from a query. We can extend this functionality by creating pagination. This
  allows us to meter the return values into set chunks. This is used frequently
  when interacting with a database through a mediating RESTful API. For example to
  return values from endpoints such as:

  ```
  /api/courses?pageNumber=2&pageSize=10
  ```

  To do this you pass two values as query parameters

  ```js
  const pageNumber = 2;
  const pageSize = 10;

  async function getCourses() {
    const courses = await Course.find()
      .skip(pageNumber - 1 * pageSize)
      .limit(pageSize);
    console.log(courses);
  }
  ```


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

  ![queue.svg](queue.svg)

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

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

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

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

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

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

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

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

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

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

  ## Use cases

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

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

  # Queues

  _Visualization of the queue data structure_

  ![queue.svg](queue.svg)

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

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

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

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

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

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

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

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

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

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

  ## Use cases

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


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

  Bash will interpret everything in the string as a literal:

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

  ## Double-quotes

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

  ```bash
  $pointlessVar='directory'

  echo "The ${pointlessVar}"

  # The directory is /home/thomas
  ```

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

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

  # Quote marks in Bash

  ## Single-quotes (aka _strong_ quotes)

  Bash will interpret everything in the string as a literal:

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

  ## Double-quotes

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

  ```bash
  $pointlessVar='directory'

  echo "The ${pointlessVar}"

  # The directory is /home/thomas
  ```

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


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

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

  ## REST

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

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

  ### Key constraints

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

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

  ## Example

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

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

  // Add: PATCH and explain differenct from PUT

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

  # RESTful APIs

  ## Definition of an API

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

  ## REST

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

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

  ### Key constraints

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

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

  ## Example

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

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

  // Add: PATCH and explain differenct from PUT


path: zk/Read.md
sortable_path: zkRead.md
title: read
checksum: 4880d98c77c081d64c56a1cd89e8f03f7a42ee91b25a42725994ca2026a56f25
created: 2024-03-30 09:03:20.731255311+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
lead:
  The primary use of `read` is to capture user input from `stdin`. It can also be
  used to parse strings or files that are redirected to it (with `<` and `<<`) or
  piped to it. In each case, what is read is stored as a variable.

body:
  The primary use of `read` is to capture user input from `stdin`. It can also be
  used to parse strings or files that are redirected to it (with `<` and `<<`) or
  piped to it. In each case, what is read is stored as a variable.

  `read` will parse line by line using a space (`\n`) as the default delimiter.
  You can use IFS to parse by other characters and/or
  [split the contents into an array](Split_into_array.md).

  ## Example of capturing user input

  When we use `read` to gather user input, the script will pause until the input
  is provided.

  ```bash
  echo "What is your name?"
  read name

  echo "What is your password?"
  read -s pass

  read

  ```

  > If you don't specify variables, `read` will automatically parse using
  > whitespace

  ## Example of piping to read

  Here we use [find](Find.md) to collate the files in
  the current directory and then pipe them to read.

  ```bash
  find -type -f  -not -path "./.git/" | read $fname
  ```

  ## Example of parsing a file

  We will typically read from a source and then do something with each variable
  that `read` returns, e.g:

  ```bash
  while read line; do
    if [ var == 'something' ]; then
      # do something
  done < './input-file.txt
  ```

  ## $REPLY

  If you do not assign a variable name to store the value that `read` reads a
  default (`$REPLY`) is applied. You can reference this value in your code.

  For example the following loop does something if `$REPLY` is equal to an empty
  string:

  ```bash
  while read;
  do
      ((count++))
      if [[ -z "$REPLY" ]]; then
          echo "$count"
      fi
  done < "$input
  ```

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

  # read

  The primary use of `read` is to capture user input from `stdin`. It can also be
  used to parse strings or files that are redirected to it (with `<` and `<<`) or
  piped to it. In each case, what is read is stored as a variable.

  `read` will parse line by line using a space (`\n`) as the default delimiter.
  You can use IFS to parse by other characters and/or
  [split the contents into an array](Split_into_array.md).

  ## Example of capturing user input

  When we use `read` to gather user input, the script will pause until the input
  is provided.

  ```bash
  echo "What is your name?"
  read name

  echo "What is your password?"
  read -s pass

  read

  ```

  > If you don't specify variables, `read` will automatically parse using
  > whitespace

  ## Example of piping to read

  Here we use [find](Find.md) to collate the files in
  the current directory and then pipe them to read.

  ```bash
  find -type -f  -not -path "./.git/" | read $fname
  ```

  ## Example of parsing a file

  We will typically read from a source and then do something with each variable
  that `read` returns, e.g:

  ```bash
  while read line; do
    if [ var == 'something' ]; then
      # do something
  done < './input-file.txt
  ```

  ## $REPLY

  If you do not assign a variable name to store the value that `read` reads a
  default (`$REPLY`) is applied. You can reference this value in your code.

  For example the following loop does something if `$REPLY` is equal to an empty
  string:

  ```bash
  while read;
  do
      ((count++))
      if [[ -z "$REPLY" ]]; then
          echo "$count"
      fi
  done < "$input
  ```


path: zk/Rebasing.md
sortable_path: zkRebasing.md
title: Rebasing
checksum: be09e17373363834833d5deb64d2732b4c33199b79b14ab0e6dfd63676670f80
created: 2024-03-30 09:03:20.745468768+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  Rebasing is a way to integrate changes from one branch into another. In this
  regarding it is like merging a branch B into another branch A. However rebasing
  differs from normal merging in the way in which it modifies the Git history.

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

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

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

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

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

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

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

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

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

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

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

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

  ## Benefits, use-cases

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

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

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

  When to use one over the other:

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

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

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

  ## Syntax

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

  ```
  git rebase main
  ```

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

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

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

  ```
  git rebase --continue
  ```

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

  ```
  git rebase --skip
  ```

  Or stop the whole process:

  ```
  git rebase --abort
  ```

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

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

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

  c33acc84f06fcb94e0e87d9adb240c038da6d71c
  ```

  ## Golden rule of rebasing

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

  ## Difference from cherry-picking

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

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

  ## Squashing commits

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

  We use the interactive rebase tool for this.

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

  Then run:

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

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

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

  ### Example

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

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

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

  This displays:

  ```
  pick xy
  pick aa
  ```

  Change this to:

  ```
  pick xy
  squash aa
  ```

  Now `xy == aa`

  ### Another example

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

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

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

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

  ## `git pull rebase`

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

  ```
  git pull --rebase
  ```

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

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

  # Rebasing

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

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

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

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

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

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

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

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

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

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

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

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

  ## Benefits, use-cases

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

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

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

  When to use one over the other:

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

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

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

  ## Syntax

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

  ```
  git rebase main
  ```

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

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

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

  ```
  git rebase --continue
  ```

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

  ```
  git rebase --skip
  ```

  Or stop the whole process:

  ```
  git rebase --abort
  ```

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

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

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

  c33acc84f06fcb94e0e87d9adb240c038da6d71c
  ```

  ## Golden rule of rebasing

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

  ## Difference from cherry-picking

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

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

  ## Squashing commits

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

  We use the interactive rebase tool for this.

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

  Then run:

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

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

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

  ### Example

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

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

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

  This displays:

  ```
  pick xy
  pick aa
  ```

  Change this to:

  ```
  pick xy
  squash aa
  ```

  Now `xy == aa`

  ### Another example

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

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

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

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

  ## `git pull rebase`

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

  ```
  git pull --rebase
  ```

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


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

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

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

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

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

  For example:

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

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

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

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

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

  # Recipricols

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

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

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

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

  For example:

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

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

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

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


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

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

  ## Why use recursive functions?

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

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

  ## Base condition

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

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

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

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

  recurse();
  ```

  ## Demonstrations

  ### Countdown

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

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

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

  countDown(4);
  ```

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

  Each stage in the process is noted below:

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

  ### Finding factorials

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

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

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

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

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

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

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

  let num = 3;

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

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

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

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

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

  ## Schema

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

  ## Why use recursive functions?

  Recursion is made for solving problems that can be broken down into smaller,
  repetitive problems. It is especially good for working on things that have many
  possible branches but are too complex for an iterative approach or too costly in
  terms of memory and time complexity.

  Recursive programming differs from **iterative** programming but both have
  similar use cases. Looping is a canonical example of working iteratively.

  ## Base condition

  > Once a condition is met, the function stops calling itself. This is called a
  > base condition.

  Because recursion has the potential for infinity, to use it, we must specify a
  point at which it ends. However as we are not using an iterative approach we
  cannot rely on `while` or `foreach` to specify the boundaries of its operation.
  We call this the **base condition** and this will typically be specified using
  conditional logic.

  The schema for a recursive function with a base condition is:

  ```jsx
  function recurse() {
    if (condition) {
      recurse();
    } else {
      // stop calling recurse()
    }
  }

  recurse();
  ```

  ## Demonstrations

  ### Countdown

  ```jsx
  // program to count down numbers to 1
  function countDown(number) {
    // display the number
    console.log(number);

    // decrease the number value
    let newNumber = number - 1;

    // base case
    if (newNumber > 0) {
      countDown(newNumber);
    }
  }

  countDown(4);
  ```

  - This code takes `4` as it's input and then outputs a countdown returning:
    `4, 3, 2, 1`
  - In each iteration, the number value is decreased by 1
  - The base condition is `newNumber > 0` . This breaks the recursive loop once
    the output reaches `1` and stops it continuing into negative integers.

  Each stage in the process is noted below:

  ```
  countDown(4) prints 4 and calls countDown(3)
  countDown(3) prints 3 and calls countDown(2)
  countDown(2) prints 2 and calls countDown(1)
  countDown(1) prints 1 and calls countDown(0)
  ```

  ### Finding factorials

  > The factorial of a positive integer **n** is the product of all the positive
  > integers less than or equal to **n**.

  To arrive at the factorial of **n** you subtract 1 from **n** and multiply the
  result of the subtraction by **n**. You repeat until the subtractive process
  runs out of positive integers. For example, if 4 is **n,** the factorial of
  **n** is **24:**

  $$ 4 _ 3 _ 2 \*1 $$

  4 multiplied by 3 gives you 12, 12 multiplied by 2 gives you 24. 24 multiplied
  by 1 is 24.

  This is clearly a process that could be implemented with a recursive function:

  ```js
  // program to find the factorial of a number
  function factorial(x) {
    // if number is 0
    if (x === 0) {
      return 1;
    }

    // if number is positive
    else {
      return x * factorial(x - 1);
    }
  }

  let num = 3;

  // calling factorial() if num is non-negative
  if (num > 0) {
    let result = factorial(num);
    console.log(`The factorial of ${num} is ${result}`);
  }
  ```

  ![javascript-factorial 1.png](javascript-factorial%201.png)


path: zk/Redirect_to_dev_null.md
sortable_path: zkRedirect_to_dev_null.md
title: Redirecting to /dev/null
lead: You'll see the following a lot when reading shell scripts:
checksum: 1864a7e2ce0dd078e01afeec825f780ffbceb38790e093fb936a971e522965c6
created: 2024-03-30 09:03:20.77646325+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  You'll see the following a lot when reading shell scripts:

  ```bash
  [some_command] > /dev/null 2>&1
  ```

  This is a redirection statement. It is redirecting data to the `null` device on
  Unix systems. Basically to a black hole or shredder where you can't access it
  because you don't want it to be output to `stdout`.

  The `2>&1` argument is the content: any errors that the program may generate and
  try to show in stout. Notice we are using the
  [file descriptors](File_descriptors_and_redirection.md)
  `1` and `2`.

  If you just want the errors regardless of whether they appear in `stdout` you
  do:

  ```bash
  [some_command] > /dev/null 2>
  ```

  ## Example

  I have used this in my Mongo start-up script:

  ```
  mongodb-compass > /dev/null 2>&1
  ```

  Here, I just want the MongoDB Compass application to start, I don't care if it
  wants to output complaints to the stout.

raw_content:
  ---
  tags:
    - shell
  ---

  # Redirecting to `/dev/null`

  You'll see the following a lot when reading shell scripts:

  ```bash
  [some_command] > /dev/null 2>&1
  ```

  This is a redirection statement. It is redirecting data to the `null` device on
  Unix systems. Basically to a black hole or shredder where you can't access it
  because you don't want it to be output to `stdout`.

  The `2>&1` argument is the content: any errors that the program may generate and
  try to show in stout. Notice we are using the
  [file descriptors](File_descriptors_and_redirection.md)
  `1` and `2`.

  If you just want the errors regardless of whether they appear in `stdout` you
  do:

  ```bash
  [some_command] > /dev/null 2>
  ```

  ## Example

  I have used this in my Mongo start-up script:

  ```
  mongodb-compass > /dev/null 2>&1
  ```

  Here, I just want the MongoDB Compass application to start, I don't care if it
  wants to output complaints to the stout.


path: zk/Redirection.md
sortable_path: zkRedirection.md
title: Redirection
lead: ## Redirecting outputs
checksum: e64c3fd247bb692dbe02ecb5f5d645298857b8d8675be4a8a9e3532475b2fc00
created: 2024-03-30 09:03:20.788996785+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["shell"]}
body:
  ## Redirecting outputs

  The symbol `>` is called the **redirection operator** because it redirects
  `stdout` to another program or file. You most frequently use this when you want
  to save contents to a file rather than standard output.

  ```bash
  ls | grep d* > result.txt
  ```

  ### Combining redirection with file escriptors

  It is common practice to combine redirection with the
  [file descriptors](File_descriptors.md) to redirect
  the output of `stdout` and `stderr`. A common case is to
  [redirect error output to `/dev/null`](Redirect_to_dev_null.md).

  Redirection defaults to interpreting `>` as the redirection of `stdout` (`1`);

  ## Redirecting inputs

  We can also switch the direction of the redirection symbol and pass in a file to
  a command rather than command ouput to a file:

  ```bash
  sql-processing-program < data.sql
  ```

  We can redirect a string with three carets:

  ```bash
  program <<< "this is a string input"
  ```

  ## Appending

  We use `>>` to append contents on the next available line of a pre-existing
  file. Continuing on from the example above:

  ```bash
  echo 'These are the files I just grepped' >> result.txt
  ```

raw_content:
  ---
  tags:
    - shell
  ---

  # Redirection

  ## Redirecting outputs

  The symbol `>` is called the **redirection operator** because it redirects
  `stdout` to another program or file. You most frequently use this when you want
  to save contents to a file rather than standard output.

  ```bash
  ls | grep d* > result.txt
  ```

  ### Combining redirection with file escriptors

  It is common practice to combine redirection with the
  [file descriptors](File_descriptors.md) to redirect
  the output of `stdout` and `stderr`. A common case is to
  [redirect error output to `/dev/null`](Redirect_to_dev_null.md).

  Redirection defaults to interpreting `>` as the redirection of `stdout` (`1`);

  ## Redirecting inputs

  We can also switch the direction of the redirection symbol and pass in a file to
  a command rather than command ouput to a file:

  ```bash
  sql-processing-program < data.sql
  ```

  We can redirect a string with three carets:

  ```bash
  program <<< "this is a string input"
  ```

  ## Appending

  We use `>>` to append contents on the next available line of a pre-existing
  file. Continuing on from the example above:

  ```bash
  echo 'These are the files I just grepped' >> result.txt
  ```


path: zk/Reducing_fractions.md
sortable_path: zkReducing_fractions.md
title: Reducing fractions to their lowest terms
checksum: 703afbdd4fe816aed30ce456b551228944ce7cd82547bdac44fba35c544b2362
created: 2024-03-30 09:03:20.801961098+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra","fractions"]}
lead:
  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

body:
  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

  > Whenever we reduce a fraction, the resultant fraction will always be
  > [equivalent](Equivalent%20fractions.md) to the fraction we started with.

  Thus the fraction $\frac{2}{3}$ is reduced to its lowest terms because the
  greatest common divisor is 1. Neither the numerator or the denominator can be
  reduced to any lower terms. In contrast, the fraction $\frac{4}{6}$ is not
  reduced to its lowest terms because the greatest common divisor of both 4 and 6
  is 2, not 1.

  ### 1. Reducing with repeated application of divisors

  The following demonstrates the process of reducing a fraction to its lowest
  terms in a series of steps:

  $$
  \\frac{18}{24} = \frac{18/2}{24/2} = \frac{9}{12} = \frac{9/3}{12/3} = \frac{3}{4}
  $$

  \_Once we get to $\frac{3}{4}$ the greatest common divisor is 1, therefore
  $\frac{18}{24}$ has been reduced to its lowest terms \_.

  ### 2. Reducing in one step with the highest common divisor

  In the previous example the reduction took two steps: first we divided by two
  and then we divided by three. There is a more efficient way: find the
  [highest common divisor](Factors%20and%20divisors.md#greatest-common-divisor) of
  the numerator and denominator and then use this as the basis for the reduction.
  With this method, the reduction can be completed in a single step.

  The greatest common divisor of 18 and 24 is 6, thus:

  $$
  \\frac{18}{24} = \frac{18/6}{24/6} = \frac{3}{4}
  $$

  Note how our earlier two divisors 2 and 3 are
  [factors](Factors%20and%20divisors.md#factors) of 6, showing the consistency
  between the two methods.

  ### 3. Reducing with factors and cancellation

  The two methods above are not very systematic and are quite heuristic. The third
  approach is more systematic and relies on the
  [interchangeability of factors and divisors](Factors%20and%20divisors.md).

  Instead of thinking asking what is the greatest common divisor of 18 and 24 we
  could ask: which single number can we multiply by to get 18 and 24? Obviously
  both numbers are in the six times table. This is therefore to say that 6 is a
  [factor](Factors%20and%20divisors.md#factors) of both: we can multiply some
  number by 6 to arrive at both 18 and 24. The numbers are 3 and 4 respectively:

  $$
  \\begin{split}
  3 \cdot 6 = 18 \\
  4 \cdot 6  = 24
  \\end{split}
  $$

  Here, 3 and 4 are the multiplicands of the factor 6. As $\frac{3}{4}$ doesn't
  have a lower common factor, it is therefore defined in its lowest terms.

  Once we have reached this point, we no longer need the common factor 6, we can
  therefore cancel it out, leaving the multiplicands as the reduced fraction:

  $$
  \\begin{split}
  3  \cancel{\cdot6= 18}\\
  4  \cancel{\cdot6= 24}
  \\end{split}
  $$

  ### 4. Reducing with prime factorisation

  This is still a bit long-winded however particularly when finding the factors of
  larger numbers because we have to go through the factors of both numbers to find
  the largest held in common.

  A better method is to utilise [prime factorization](Prime%20factorization.md)
  combined with the canceling technique.

  First we find the prime factors of both the numerator and denominator:
  ![drawio-Page-7.drawio.png](drawio-Page-7.drawio.png)

  This gives us:

  $$
  \\frac{18}{24} = \frac{2 \cdot 3 \cdot 3}{2 \cdot 2 \cdot 2 \cdot 3}
  $$

  We then cancel out the factors held in common between the numerator and
  denominator:

  $$
  \\frac{\cancel{2} \cdot \cancel{3} \cdot 3}{\cancel{2} \cdot 2 \cdot 2 \cdot \cancel{3}}
  $$

  This gives us:

  $$
  \\frac{3}{2 \cdot 2}
  $$

  We then simplify the fraction as normal to its lowest term (conducting any
  multiplications required by what is left from the prime factorization):

  $$
  \\frac{3}{4}
  $$

  ## Reducing fractions that contain variables

  Superficially this looks to be more difficult but in fact we can apply the same
  prime factorization method to get the result.

  ### Demonstration

  _Reduce the following fraction to its lowest terms: $$\frac{25a^3b}{40a^2b^3}$$_

  The prime factors of the numerator and denominator:

  $$
  \\begin{split}
  25 = {5, 5} \\
  40 = {2,2,2,5}
  \\end{split}
  $$

  Now we apply canceling but we include the variable parts, treating them exactly
  the same as the coefficients. We break them out of their exponents however.

  $$\frac{25a^3b}{40a^2b^3} =\frac{5 \cdot 5 \cdot a \cdot a \cdot a \cdot b}{2 \cdot 2 \cdot 2 \cdot 5 \cdot a \cdot a \cdot b \cdot b \cdot b }$$

  Canceled:

  $$\frac{\cancel{5} \cdot 5 \cdot  \cancel{a} \cdot \cancel{a} \cdot a \cdot \cancel{b}}{2 \cdot 2 \cdot 2 \cdot \cancel{5} \cdot \cancel{a} \cdot \cancel{a} \cdot \cancel{b} \cdot b \cdot b }$$

  Which gives us:

  $$
  \\frac{5 \cdot a}{2 \cdot 2 \cdot 2 \cdot b \cdot b} = \frac{5a}{8b^2}
  $$

  ## Reducing fractions that contain negative values

  _Reduce the following fraction to its lowest terms: $$\frac{14y^5}{-35y^3}$$_

  - This fraction is an instance of a
    [fraction with unlike terms](Handling%20negative%20fractions.md#fractions-with-unlike-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

    ![draw.io-Page-8.drawio.png](draw.io-Page-8.drawio.png)

  - Cancel the coefficients and variable parts

    $$
    \\frac{14y^5}{-35y^3}=\frac{5 \cdot 7 \cdot 2 \cdot y \cdot y \cdot y \cdot y \cdot y}{-5 \cdot 7  \cdot y \cdot y \cdot y} = - \frac{2y^2}{5}
    $$

  _Reduce the following fraction to its lowest terms:
  $$\frac{- 12xy^2}{ - 18xy^2}$$_

  - This fraction is an instance of a
    [fraction with like terms](Handling%20negative%20fractions.md#fractions-with-like-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

  ![draw.io-Page-8.drawio 1.png](draw.io-Page-8.drawio%201.png)

  - Cancel the coefficients and variable parts

    $$

    * \\frac{12xy^2}{18xy^2}=\frac{3 \cdot 2 \cdot 2 \cdot x \cdot y \cdot y}{3 \cdot 7  \cdot 3 \cdot 2 \cdot x \cdot x \cdot y} = - \frac{2y}{3x}
    $$

raw_content:
  ---
  tags:
    - prealgebra
    - fractions
  ---

  ## Reducing fractions to their lowest terms

  > A fraction is said to be _reduced to its lowest terms_ if the
  > [greatest common divisor](Factors%20and%20divisors.md#greatest-common-divisor)
  > of the numerator and the denominator is $1$.

  > Whenever we reduce a fraction, the resultant fraction will always be
  > [equivalent](Equivalent%20fractions.md) to the fraction we started with.

  Thus the fraction $\frac{2}{3}$ is reduced to its lowest terms because the
  greatest common divisor is 1. Neither the numerator or the denominator can be
  reduced to any lower terms. In contrast, the fraction $\frac{4}{6}$ is not
  reduced to its lowest terms because the greatest common divisor of both 4 and 6
  is 2, not 1.

  ### 1. Reducing with repeated application of divisors

  The following demonstrates the process of reducing a fraction to its lowest
  terms in a series of steps:

  $$
  \\frac{18}{24} = \frac{18/2}{24/2} = \frac{9}{12} = \frac{9/3}{12/3} = \frac{3}{4}
  $$

  \_Once we get to $\frac{3}{4}$ the greatest common divisor is 1, therefore
  $\frac{18}{24}$ has been reduced to its lowest terms \_.

  ### 2. Reducing in one step with the highest common divisor

  In the previous example the reduction took two steps: first we divided by two
  and then we divided by three. There is a more efficient way: find the
  [highest common divisor](Factors%20and%20divisors.md#greatest-common-divisor) of
  the numerator and denominator and then use this as the basis for the reduction.
  With this method, the reduction can be completed in a single step.

  The greatest common divisor of 18 and 24 is 6, thus:

  $$
  \\frac{18}{24} = \frac{18/6}{24/6} = \frac{3}{4}
  $$

  Note how our earlier two divisors 2 and 3 are
  [factors](Factors%20and%20divisors.md#factors) of 6, showing the consistency
  between the two methods.

  ### 3. Reducing with factors and cancellation

  The two methods above are not very systematic and are quite heuristic. The third
  approach is more systematic and relies on the
  [interchangeability of factors and divisors](Factors%20and%20divisors.md).

  Instead of thinking asking what is the greatest common divisor of 18 and 24 we
  could ask: which single number can we multiply by to get 18 and 24? Obviously
  both numbers are in the six times table. This is therefore to say that 6 is a
  [factor](Factors%20and%20divisors.md#factors) of both: we can multiply some
  number by 6 to arrive at both 18 and 24. The numbers are 3 and 4 respectively:

  $$
  \\begin{split}
  3 \cdot 6 = 18 \\
  4 \cdot 6  = 24
  \\end{split}
  $$

  Here, 3 and 4 are the multiplicands of the factor 6. As $\frac{3}{4}$ doesn't
  have a lower common factor, it is therefore defined in its lowest terms.

  Once we have reached this point, we no longer need the common factor 6, we can
  therefore cancel it out, leaving the multiplicands as the reduced fraction:

  $$
  \\begin{split}
  3  \cancel{\cdot6= 18}\\
  4  \cancel{\cdot6= 24}
  \\end{split}
  $$

  ### 4. Reducing with prime factorisation

  This is still a bit long-winded however particularly when finding the factors of
  larger numbers because we have to go through the factors of both numbers to find
  the largest held in common.

  A better method is to utilise [prime factorization](Prime%20factorization.md)
  combined with the canceling technique.

  First we find the prime factors of both the numerator and denominator:
  ![drawio-Page-7.drawio.png](drawio-Page-7.drawio.png)

  This gives us:

  $$
  \\frac{18}{24} = \frac{2 \cdot 3 \cdot 3}{2 \cdot 2 \cdot 2 \cdot 3}
  $$

  We then cancel out the factors held in common between the numerator and
  denominator:

  $$
  \\frac{\cancel{2} \cdot \cancel{3} \cdot 3}{\cancel{2} \cdot 2 \cdot 2 \cdot \cancel{3}}
  $$

  This gives us:

  $$
  \\frac{3}{2 \cdot 2}
  $$

  We then simplify the fraction as normal to its lowest term (conducting any
  multiplications required by what is left from the prime factorization):

  $$
  \\frac{3}{4}
  $$

  ## Reducing fractions that contain variables

  Superficially this looks to be more difficult but in fact we can apply the same
  prime factorization method to get the result.

  ### Demonstration

  _Reduce the following fraction to its lowest terms: $$\frac{25a^3b}{40a^2b^3}$$_

  The prime factors of the numerator and denominator:

  $$
  \\begin{split}
  25 = {5, 5} \\
  40 = {2,2,2,5}
  \\end{split}
  $$

  Now we apply canceling but we include the variable parts, treating them exactly
  the same as the coefficients. We break them out of their exponents however.

  $$\frac{25a^3b}{40a^2b^3} =\frac{5 \cdot 5 \cdot a \cdot a \cdot a \cdot b}{2 \cdot 2 \cdot 2 \cdot 5 \cdot a \cdot a \cdot b \cdot b \cdot b }$$

  Canceled:

  $$\frac{\cancel{5} \cdot 5 \cdot  \cancel{a} \cdot \cancel{a} \cdot a \cdot \cancel{b}}{2 \cdot 2 \cdot 2 \cdot \cancel{5} \cdot \cancel{a} \cdot \cancel{a} \cdot \cancel{b} \cdot b \cdot b }$$

  Which gives us:

  $$
  \\frac{5 \cdot a}{2 \cdot 2 \cdot 2 \cdot b \cdot b} = \frac{5a}{8b^2}
  $$

  ## Reducing fractions that contain negative values

  _Reduce the following fraction to its lowest terms: $$\frac{14y^5}{-35y^3}$$_

  - This fraction is an instance of a
    [fraction with unlike terms](Handling%20negative%20fractions.md#fractions-with-unlike-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

    ![draw.io-Page-8.drawio.png](draw.io-Page-8.drawio.png)

  - Cancel the coefficients and variable parts

    $$
    \\frac{14y^5}{-35y^3}=\frac{5 \cdot 7 \cdot 2 \cdot y \cdot y \cdot y \cdot y \cdot y}{-5 \cdot 7  \cdot y \cdot y \cdot y} = - \frac{2y^2}{5}
    $$

  _Reduce the following fraction to its lowest terms:
  $$\frac{- 12xy^2}{ - 18xy^2}$$_

  - This fraction is an instance of a
    [fraction with like terms](Handling%20negative%20fractions.md#fractions-with-like-terms).

  - Apply [Prime factorization](Prime%20factorization.md):

  ![draw.io-Page-8.drawio 1.png](draw.io-Page-8.drawio%201.png)

  - Cancel the coefficients and variable parts

    $$

    * \\frac{12xy^2}{18xy^2}=\frac{3 \cdot 2 \cdot 2 \cdot x \cdot y \cdot y}{3 \cdot 7  \cdot 3 \cdot 2 \cdot x \cdot x \cdot y} = - \frac{2y}{3x}
    $$


path: zk/Regular_expressions_in_SQL.md
sortable_path: zkRegular_expressions_in_SQL.md
title: Regular expressions in SQL
lead:
  ```sql
  SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

checksum: 67e9c050597a6c540cbe07fb843e8fae1d4cb7866003649ac073afdd1563e05f
created: 2024-03-30 09:03:20.887464229+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["SQL","relational-databases","regex"]}
body:
  ```sql
  SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

  Guyana
  Mexico
  Myanmar
  ```

raw_content:
  ---
  tags: [SQL, relational-databases, regex]
  ---

  # Regular expressions in SQL

  ```sql
  SELECT name FROM country WHERE name RLIKE '[xy][ai]' ORDER BY name;

  Guyana
  Mexico
  Myanmar
  ```


path: zk/Reiteration.md
sortable_path: zkReiteration.md
title: Reiteration
checksum: ea9b8e71786e265aab7d0a50515cb159b3afc4a3ccb47c2e939ccedb9d2915d7
created: 2024-03-30 09:03:20.890874329+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":[]}
lead:
  **Reiteration (R)** allows us to restate any proposition already in the proof
  within the main proof or a more deeply nested sub-proof. Reiteration allows us
  to reuse any assumptions, or propositions derived from assumptions, without
  having to introduce a new dependency with another assumption.

body:
  **Reiteration (R)** allows us to restate any proposition already in the proof
  within the main proof or a more deeply nested sub-proof. Reiteration allows us
  to reuse any assumptions, or propositions derived from assumptions, without
  having to introduce a new dependency with another assumption.

  ![](/img/reiteration.png)

raw_content:
  ---
  tags: []
  ---

  # Reiteration

  **Reiteration (R)** allows us to restate any proposition already in the proof
  within the main proof or a more deeply nested sub-proof. Reiteration allows us
  to reuse any assumptions, or propositions derived from assumptions, without
  having to introduce a new dependency with another assumption.

  ![](/img/reiteration.png)


path: zk/Relation_between_kernel_and_CPU.md
sortable_path: zkRelation_between_kernel_and_CPU.md
title: Relation between the kernel and CPU
checksum: 932e2ae629c9d9a25ed03d37a9f10bd952212ef231f4b486ea1f9940a7e1b44c
created: 2024-03-30 09:03:20.896906687+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["kernel","CPU"]}
lead:
  It can be confusing to understand how the kernel and CPU interact with one
  another. Whilst it is true to say the kernel mediates between the hardware and
  user processes, this led me to think that the kernel was somehow 'over and
  above' the actions of the CPU. This is wrong and if you think about it, how
  could this be since any process, kernel included, requires the processor? The
  kernel is executed by and loaded into the CPU just like any other instruction in
  the
  [fetch, decode, execute cycle](Fetch_decode_execute.md)
  of the CPU.

body:
  It can be confusing to understand how the kernel and CPU interact with one
  another. Whilst it is true to say the kernel mediates between the hardware and
  user processes, this led me to think that the kernel was somehow 'over and
  above' the actions of the CPU. This is wrong and if you think about it, how
  could this be since any process, kernel included, requires the processor? The
  kernel is executed by and loaded into the CPU just like any other instruction in
  the
  [fetch, decode, execute cycle](Fetch_decode_execute.md)
  of the CPU.

  However as a process, the kernel is the 'first amongst equals' given that it is
  the core embodiment of the operating system. At boot time, the kernel is
  injected into memory and at this point the CPU _looks to this address_ in memory
  in order to source its first instruction. That's how the kernel gets going. It
  is the first instruction that the CPU fetches and this is what allows the kernel
  to play its mediatory role. However most of the fetch, decode, execute cycles of
  the CPU take place independently of the kernel.

  ![](/img/kernel-cpu-interaction.svg)

  > Fetch decode and execute refer to processor pipeline stages. They occur
  > automatically as part of normal processor operation, the kernel doesn’t
  > generally have any direct control over how that happens...When the boot loader
  > loads the kernel, it points the CPU’s program counter to an entry point in the
  > kernel’s code. From there, the CPU will continue executing (fetching decoding
  > and executing) kernel code until you point the program counter to a userspace
  > program, where it will continue executing userspace code until an interrupt
  > points the program counter back into kernel code. That’s basically what the
  > CPU will be doing from boot up to shut down; switching between executing
  > kernel code and executing userspace code
  > ([Reddit]())

  This is because of [context switching](), when the CPU is running its cycle, the
  kernel is idle waiting for it to complete. Once control switches back to the
  kernel it can then run its next duty which will be either process, memory or
  device management or system calls. Then it will hand control over to either the
  processor or user space.

raw_content:
  ---
  tags:
    - kernel
    - CPU
  ---

  # Relation between the kernel and CPU

  It can be confusing to understand how the kernel and CPU interact with one
  another. Whilst it is true to say the kernel mediates between the hardware and
  user processes, this led me to think that the kernel was somehow 'over and
  above' the actions of the CPU. This is wrong and if you think about it, how
  could this be since any process, kernel included, requires the processor? The
  kernel is executed by and loaded into the CPU just like any other instruction in
  the
  [fetch, decode, execute cycle](Fetch_decode_execute.md)
  of the CPU.

  However as a process, the kernel is the 'first amongst equals' given that it is
  the core embodiment of the operating system. At boot time, the kernel is
  injected into memory and at this point the CPU _looks to this address_ in memory
  in order to source its first instruction. That's how the kernel gets going. It
  is the first instruction that the CPU fetches and this is what allows the kernel
  to play its mediatory role. However most of the fetch, decode, execute cycles of
  the CPU take place independently of the kernel.

  ![](/img/kernel-cpu-interaction.svg)

  > Fetch decode and execute refer to processor pipeline stages. They occur
  > automatically as part of normal processor operation, the kernel doesn’t
  > generally have any direct control over how that happens...When the boot loader
  > loads the kernel, it points the CPU’s program counter to an entry point in the
  > kernel’s code. From there, the CPU will continue executing (fetching decoding
  > and executing) kernel code until you point the program counter to a userspace
  > program, where it will continue executing userspace code until an interrupt
  > points the program counter back into kernel code. That’s basically what the
  > CPU will be doing from boot up to shut down; switching between executing
  > kernel code and executing userspace code
  > ([Reddit]())

  This is because of [context switching](), when the CPU is running its cycle, the
  kernel is idle waiting for it to complete. Once control switches back to the
  kernel it can then run its next duty which will be either process, memory or
  device management or system calls. Then it will hand control over to either the
  processor or user space.


path: zk/Relational_database_architecture.md
sortable_path: zkRelational_database_architecture.md
title: Relational database architecture
lead: Tables, fields and records are the basic building blocks of databases
checksum: bcdb6e8a5730c426ba44faf845f9daaa441a57cbbf3a69e03f5141e366b0d58b
created: 2024-03-30 09:03:20.905418741+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["relational-databases"]}
body:
  Tables, fields and records are the basic building blocks of databases

  ![](/img/FL-Databases-1.5_terminology.gif)

  ## Table

  A group of similar data with rows for **records** and columns for each
  **field**.

  ## Record

  A horizontal row: a collection of items which may be of different data types all
  relating to the individual or object that the record describes. A single _entry_
  in the table. Sometimes called **row** interchangeably.

  ## Field

  A vertical column: stores a single particular unit of data for each record. Each
  field must use the same data type. Sometimes called **field** interchangeably.

  Each individual field has **properties:** such as the data type, length or the
  total memory allocation.

raw_content:
  ---
  tags: [relational-databases]
  ---

  # Relational database architecture

  Tables, fields and records are the basic building blocks of databases

  ![](/img/FL-Databases-1.5_terminology.gif)

  ## Table

  A group of similar data with rows for **records** and columns for each
  **field**.

  ## Record

  A horizontal row: a collection of items which may be of different data types all
  relating to the individual or object that the record describes. A single _entry_
  in the table. Sometimes called **row** interchangeably.

  ## Field

  A vertical column: stores a single particular unit of data for each record. Each
  field must use the same data type. Sometimes called **field** interchangeably.

  Each individual field has **properties:** such as the data type, length or the
  total memory allocation.


path: zk/Remote_tracking_branches.md
sortable_path: zkRemote_tracking_branches.md
title: Remote tracking branches
checksum: 775d9cfcc8eb49533dfa647d6fc6911b93fc101e8c2d79da117d0865f0bb5f3b
created: 2024-03-30 09:03:20.909141849+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git"]}
lead:
  A remote tracking branch is a **local** snapshot or reference to the state of a
  branch on a remote repository.

body:
  A remote tracking branch is a **local** snapshot or reference to the state of a
  branch on a remote repository.

  When you clone a remote repository, Git automatically creates remote tracking
  branches for all the branches on the remote repository.

  The remote tracking branches have the prefix `origin/` followed by the name of
  the remote branch. For example, if you clone a repository with a branch named
  `develop`, Git creates a remote tracking branch named `origin/develop`.

  When you use commands like `git fetch` and `git pull`, you are interacting with
  the remote repository and having it reflected in the remote tracking branches.

  For instance, `git fetch` makes the remote tracking branch reflect the remote
  changes so that you have a local copy.

  The remote tracking branch is not the same as a local branch. A local branch is
  a branch that may or may not exist on the remote. Once it has been pushed to the
  remote repository, a remote tracking branch will be created for its remote
  version. When you make local changes, the snapshot of the remote tracking branch
  will no longer be up to date: your local branch will be "ahead" of it. Once you
  push, the remote tracking branch snapshot is update and reflects the local state
  of the branch and the two are in sync again.

  The same is true of remote branches. When you checkout a remote branch, your
  local version of it reflects a remote tracking version of it. This goes out of
  sync with your local version when changes are made on the remote.

raw_content:
  ---
  tags: [git]
  ---

  # Remote tracking branches

  A remote tracking branch is a **local** snapshot or reference to the state of a
  branch on a remote repository.

  When you clone a remote repository, Git automatically creates remote tracking
  branches for all the branches on the remote repository.

  The remote tracking branches have the prefix `origin/` followed by the name of
  the remote branch. For example, if you clone a repository with a branch named
  `develop`, Git creates a remote tracking branch named `origin/develop`.

  When you use commands like `git fetch` and `git pull`, you are interacting with
  the remote repository and having it reflected in the remote tracking branches.

  For instance, `git fetch` makes the remote tracking branch reflect the remote
  changes so that you have a local copy.

  The remote tracking branch is not the same as a local branch. A local branch is
  a branch that may or may not exist on the remote. Once it has been pushed to the
  remote repository, a remote tracking branch will be created for its remote
  version. When you make local changes, the snapshot of the remote tracking branch
  will no longer be up to date: your local branch will be "ahead" of it. Once you
  push, the remote tracking branch snapshot is update and reflects the local state
  of the branch and the two are in sync again.

  The same is true of remote branches. When you checkout a remote branch, your
  local version of it reflects a remote tracking version of it. This goes out of
  sync with your local version when changes are made on the remote.


path: zk/Rename_a_branch.md
sortable_path: zkRename_a_branch.md
title: Rename a branch
lead: ### In local development
checksum: e8c060552e8fa8aad44a72102793c1db506b6091b9f8a57b3b216a90c49c8030
created: 2024-03-30 09:03:20.913303933+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git","procedural"]}
body:
  ### In local development

  ```bash
  git branch -m <old_name> <new_name>
  ```

  ### Update the remote

  ```bash
  git push origin -u <new_name>
  ```

raw_content:
  ---
  tags: [git, procedural]
  ---

  # Rename a branch

  ### In local development

  ```bash
  git branch -m <old_name> <new_name>
  ```

  ### Update the remote

  ```bash
  git push origin -u <new_name>
  ```


path: zk/Reset_to_remote_version.md
sortable_path: zkReset_to_remote_version.md
title: Reset to remote version of a branch
checksum: 4275e3738538e2f4224803c94c28cbb651c5bde268c007b9541dd886624806d9
created: 2024-03-30 09:03:20.918172854+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["git","procedural"]}
lead:
  The scenario: your local Git history has become corrupted in some way and you
  want a clean history based on the current state of the remote. We will
  demonstrate with `main`.

body:
  The scenario: your local Git history has become corrupted in some way and you
  want a clean history based on the current state of the remote. We will
  demonstrate with `main`.

  ```
  git fetch origin
  git reset --hard origin/main
  ```

raw_content:
  ---
  tags: [git, procedural]
  ---

  # Reset to remote version of a branch

  The scenario: your local Git history has become corrupted in some way and you
  want a clean history based on the current state of the remote. We will
  demonstrate with `main`.

  ```
  git fetch origin
  git reset --hard origin/main
  ```


path: zk/Resistance.md
sortable_path: zkResistance.md
title: Resistance
checksum: 91ef98bd45a82c1cc3815fb58f2503505744b92204b99a09f5fe903c7fd50dc7
created: 2024-03-30 09:03:20.922231712+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["physics","electricity"]}
lead:
  Resistance is opposition to the flow of current. Different materials have
  different levels of resistance. For example glass and rubber are excellent
  resistors whereas silver and copper offer little resistance to current flow. We
  utilise **resistors** to control the flow of current in a circuit.

body:
  Resistance is opposition to the flow of current. Different materials have
  different levels of resistance. For example glass and rubber are excellent
  resistors whereas silver and copper offer little resistance to current flow. We
  utilise **resistors** to control the flow of current in a circuit.

  ## Relationship between _resistance_ and _insulation_

  Resistance and insulation are not the same thing although they relate to the
  same natural phenomena. Resistance is a property of an electrical circuit
  whereas insularity is a property of substances found in the world. Similarly,
  insulators are naturally occuring materials that resist the flow of current to
  different degrees whereas a resistor is a man-made electrical component that is
  used to _control_ the flow of current in a circuit.

  ## Factors affecting resistance

  - The larger the diameter of an electric wire, the lower the electrical
    resistance to the current flow. (If we use the analogy of electricity as
    water-flow: the wider the pipe, the more water that can flow.)
  - As a conductor heats up (e.g. copper, aluminium wire), its overall resistance
    increases.

  ## Notation and scientific expression

  ### Resistance

  - We use $R$ to represent resistance
  - The unit of resistance is **ohms** ($\Omega$)

  > One ohm is the resistance of a circuit or circuit element that permits a
  > steady current flow of one
  > [amp](Current.md#formal-expression)
  > (one coulomb/second) when one
  > [volt](Voltage.md#voltage) is
  > applied to the circuit.

  ### Conductance

  - We use $G$ to represent conductance
  - The unit of conductance is **Mho** (ohm spelled backwards) ($\mho$)

  > Conductance is the ability of a material to pass electrons

  > Given that resistance is the opposite of conductance, the relation between the
  > two quantities can be expressed via a recipricol: $R = 1/G$ and $G = 1/R$

  ## Ohm's Law

  The relationship between current, resistance and voltage is expressed in
  [Ohm's Law](Ohms_Law.md).

  ## Resistors

  A resistor is an electrical component that can be used in circuits to introduce
  specific amounts to resistance where needed. This is typically done in order to
  temper the total voltage and so keep the current flowing within certain set
  parameters.

raw_content:
  ---
  tags: [physics, electricity]
  ---

  # Resistance

  Resistance is opposition to the flow of current. Different materials have
  different levels of resistance. For example glass and rubber are excellent
  resistors whereas silver and copper offer little resistance to current flow. We
  utilise **resistors** to control the flow of current in a circuit.

  ## Relationship between _resistance_ and _insulation_

  Resistance and insulation are not the same thing although they relate to the
  same natural phenomena. Resistance is a property of an electrical circuit
  whereas insularity is a property of substances found in the world. Similarly,
  insulators are naturally occuring materials that resist the flow of current to
  different degrees whereas a resistor is a man-made electrical component that is
  used to _control_ the flow of current in a circuit.

  ## Factors affecting resistance

  - The larger the diameter of an electric wire, the lower the electrical
    resistance to the current flow. (If we use the analogy of electricity as
    water-flow: the wider the pipe, the more water that can flow.)
  - As a conductor heats up (e.g. copper, aluminium wire), its overall resistance
    increases.

  ## Notation and scientific expression

  ### Resistance

  - We use $R$ to represent resistance
  - The unit of resistance is **ohms** ($\Omega$)

  > One ohm is the resistance of a circuit or circuit element that permits a
  > steady current flow of one
  > [amp](Current.md#formal-expression)
  > (one coulomb/second) when one
  > [volt](Voltage.md#voltage) is
  > applied to the circuit.

  ### Conductance

  - We use $G$ to represent conductance
  - The unit of conductance is **Mho** (ohm spelled backwards) ($\mho$)

  > Conductance is the ability of a material to pass electrons

  > Given that resistance is the opposite of conductance, the relation between the
  > two quantities can be expressed via a recipricol: $R = 1/G$ and $G = 1/R$

  ## Ohm's Law

  The relationship between current, resistance and voltage is expressed in
  [Ohm's Law](Ohms_Law.md).

  ## Resistors

  A resistor is an electrical component that can be used in circuits to introduce
  specific amounts to resistance where needed. This is typically done in order to
  temper the total voltage and so keep the current flowing within certain set
  parameters.


path: zk/Restructure_URLs.md
sortable_path: zkRestructure_URLs.md
title: AWS Lambda examples
lead: ## Reconstruct CloudFront URLs
checksum: b76654cfe8a6f2f96f6557b40766d3fedaed1dae3735eb0a6c492e55630dd426
created: 2024-03-30 09:03:20.938924551+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS","aws-lambda","backend"]}
body:
  ## Reconstruct CloudFront URLs

  ```js
  exports.handler = (event, context, callback) => {
    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, "/index.html");

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);
  };
  ```

  Let's walk through the above example making reference to the general structure
  of the
  [AWS Lambda handler function](Lambda_handler_function.md):

  1. The `event` parameter is invoked to gain access to the event that triggered
     the function. This is a CloudFront request event which is targetted with
     `event.Records[0].cf.request`
  2. We classify this request as the `olduri` since it doesn't have the form we
     want.
  3. We mutate the original request by replacing `/` with `/index.html`
  4. We then re-assign the `request.uri` value to the value of the new URI.
  5. Finally we invoke the `callback` parameter to signal the completion of the
     transformation and return the new request as the return value.

raw_content:
  ---
  tags: [AWS, aws-lambda, backend]
  ---

  # AWS Lambda examples

  ## Reconstruct CloudFront URLs

  ```js
  exports.handler = (event, context, callback) => {
    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, "/index.html");

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);
  };
  ```

  Let's walk through the above example making reference to the general structure
  of the
  [AWS Lambda handler function](Lambda_handler_function.md):

  1. The `event` parameter is invoked to gain access to the event that triggered
     the function. This is a CloudFront request event which is targetted with
     `event.Records[0].cf.request`
  2. We classify this request as the `olduri` since it doesn't have the form we
     want.
  3. We mutate the original request by replacing `/` with `/index.html`
  4. We then re-assign the `request.uri` value to the value of the new URI.
  5. Finally we invoke the `callback` parameter to signal the completion of the
     transformation and return the new request as the return value.


path: zk/Retrieve_data_from_SQL_table.md
sortable_path: zkRetrieve_data_from_SQL_table.md
title: Retrieve data from table with SQL SELECT statement
checksum: 8076a2e030e23a81229cb7843f6e5bbd8366b715eebb667a61885775ae2fff49
created: 2024-03-30 09:03:20.947544099+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["SQL","relational-databases"]}
lead:
  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

body:
  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

  _A table named `models`:_

  | modelId | name                 | cores | releaseDate |
  | ------- | -------------------- | ----- | ----------- |
  | 2       | Raspberry Pi Model B | 2     | 2022-11-19  |
  | 3       | Raspberry Pi Model C | 4     | 2022-11-25  |
  | 4       | MacBook Pro M2       | 9     | 2022-03-18  |

  ## Basic usage

  ```sql
  SELECT name FROM models
  ```

  We can pass in a comma-separated **list of fields**:

  ```sql
  SELECT name, releaseDate FROM models
  ```

  ## With parameters

  ### `WHERE`

  The `WHERE` clause specifies a search criterion. The `WHERE` clause should
  always be last in the syntax. The clauses are always written in this order:
  `FROM` followed by `WHERE`

  ```sql
  SELECT name FROM models WHERE cores > 3
  ```

  ### Compound statements

  Compound statements allow you to apply more filters to your clauses within an
  SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by
  using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` ,
  `<=` ...)

  Multiple clauses:

  ```sql
  SELECT name, ram, release_date
  FROM model
  WHERE release_date > '2018-01-01' AND ram > 512;
  ```

  More complex logic achieve with parentheses:

  ```sql
  SELECT name, cores, release_date
  FROM model
  WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
  ```

  ## Transform returned data

  We can apply **ordering** to the return data

  ```sql
  SELECT name FROM models ORDER BY name, cores
  SELECT name FROM models ORDER BY name, cores DESC
  ```

  > `ORDER BY` always comes last, after the selection and any filtering clauses
  > but _before_ a `WHERE` clause

  ## Paginate

  We can break our returned data into blocks with `LIMIT`

  ```sql
  LIMIT 5 -- Return first five items
  LIMIT 5,5 -- Return first five items from the sixth row
  ```

raw_content:
  ---
  tags: [SQL, relational-databases]
  ---

  # Retrieve data from table with SQL `SELECT` statement

  > Select data from the database. The data returned is stored in a result table
  > called the **result-set**.

  _A table named `models`:_

  | modelId | name                 | cores | releaseDate |
  | ------- | -------------------- | ----- | ----------- |
  | 2       | Raspberry Pi Model B | 2     | 2022-11-19  |
  | 3       | Raspberry Pi Model C | 4     | 2022-11-25  |
  | 4       | MacBook Pro M2       | 9     | 2022-03-18  |

  ## Basic usage

  ```sql
  SELECT name FROM models
  ```

  We can pass in a comma-separated **list of fields**:

  ```sql
  SELECT name, releaseDate FROM models
  ```

  ## With parameters

  ### `WHERE`

  The `WHERE` clause specifies a search criterion. The `WHERE` clause should
  always be last in the syntax. The clauses are always written in this order:
  `FROM` followed by `WHERE`

  ```sql
  SELECT name FROM models WHERE cores > 3
  ```

  ### Compound statements

  Compound statements allow you to apply more filters to your clauses within an
  SQL statement. SQL allows you to build complex, combinatorial `WHERE` clauses by
  using Boolean and mathematical operators (i.e `AND` , `OR` , `>` , `<` , `!=` ,
  `<=` ...)

  Multiple clauses:

  ```sql
  SELECT name, ram, release_date
  FROM model
  WHERE release_date > '2018-01-01' AND ram > 512;
  ```

  More complex logic achieve with parentheses:

  ```sql
  SELECT name, cores, release_date
  FROM model
  WHERE (manufacturer_id = 1 OR manufacturer_id = 2) AND cores >= 2;
  ```

  ## Transform returned data

  We can apply **ordering** to the return data

  ```sql
  SELECT name FROM models ORDER BY name, cores
  SELECT name FROM models ORDER BY name, cores DESC
  ```

  > `ORDER BY` always comes last, after the selection and any filtering clauses
  > but _before_ a `WHERE` clause

  ## Paginate

  We can break our returned data into blocks with `LIMIT`

  ```sql
  LIMIT 5 -- Return first five items
  LIMIT 5,5 -- Return first five items from the sixth row
  ```


path: zk/Role_of_unique_key_in_relational_databases.md
sortable_path: zkRole_of_unique_key_in_relational_databases.md
title: Unique key
checksum: 1b1a89dbadc5a0c2cb46a8adf7099790f75ec1de35ec9b70340fb33e5611fa5d
created: 2024-03-30 09:03:20.95077825+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["relational-databases"]}
lead:
  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

body:
  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

  This is essential for carrying out operations across database tables and for
  creating and deleting database entires in accordance with the
  [ACID principle](ACID_principle.md). It is also a safeguard: it means
  you can always identify a record by itself and don't have to rely on generic
  queries to identify it.

  Sometimes you will have a dedicated field such as `UNIQUE_ID` for the unique
  key. Other times you can use an existing field to fulfil that function. When an
  existing, visible column is used as the unique key it is called the **primary
  key**. Other times the unique key can be hidden from the table.

  In both cases the following constraints **must be met:**

  1. No two records can have the **same** primary key data
  1. The primary key value should **never be reused**. Thus, if a record is
     deleted from the table, it should not be re-allocated to a new record.
  1. A primary key value **must not be modified** once it has been created
  1. A primary key **must have a value**; it cannot be `null`

raw_content:
  ---
  tags: [relational-databases]
  ---

  # Unique key

  > Every table in a relational database should have a **unique key**. A unique
  > key is one **field that uniquely identifies each record**.

  This is essential for carrying out operations across database tables and for
  creating and deleting database entires in accordance with the
  [ACID principle](ACID_principle.md). It is also a safeguard: it means
  you can always identify a record by itself and don't have to rely on generic
  queries to identify it.

  Sometimes you will have a dedicated field such as `UNIQUE_ID` for the unique
  key. Other times you can use an existing field to fulfil that function. When an
  existing, visible column is used as the unique key it is called the **primary
  key**. Other times the unique key can be hidden from the table.

  In both cases the following constraints **must be met:**

  1. No two records can have the **same** primary key data
  1. The primary key value should **never be reused**. Thus, if a record is
     deleted from the table, it should not be re-allocated to a new record.
  1. A primary key value **must not be modified** once it has been created
  1. A primary key **must have a value**; it cannot be `null`


path: zk/Routing_on_link_click.md
sortable_path: zkRouting_on_link_click.md
title: Test: Routing on link click
lead: ## Component
checksum: 0935aa4e5e1e4051e4ca684aa0735d3b0fb3a555a93412746712f20724dee40b
created: 2024-03-30 09:03:20.966472926+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["javascript","react","testing"]}
body:
  ## Component

  ```jsx
  const CertificateHtmlLink = () => {
    return (
      <div className="certificate-html-link html-version-message">
        <Link className="btn btn-primary ml-2" to="/some-location">
          View HTML version
        </Link>
      </div>
    );
  };
  ```

  ## Test

  ```js
  import { render, fireEvent } from "@testing-library/react";
  import { Router } from "react-router-dom";

  describe("<CertificateHtmlLink", () => {
    it("should link to dynamic HTML certificate page URL on click event", () => {
      // Arrange:
      const history = createMemoryHistory({ initialEntries: ["/"] });

      // Act:
      const { getByText } = render(
        <Router history={history}>
          <CertificateHtmlLink to="/certificate/123" />
        </Router>
      );

      // Assert:
      expect(history.location.pathname).toBe("/");
      fireEvent.click(getByText("View HTML version"));
      expect(history.location.pathname).toBe("/certificate/123");
    });
  });
  ```

raw_content:
  ---
  tags:
    - javascript
    - react
    - testing
  ---

  # Test: Routing on link click

  ## Component

  ```jsx
  const CertificateHtmlLink = () => {
    return (
      <div className="certificate-html-link html-version-message">
        <Link className="btn btn-primary ml-2" to="/some-location">
          View HTML version
        </Link>
      </div>
    );
  };
  ```

  ## Test

  ```js
  import { render, fireEvent } from "@testing-library/react";
  import { Router } from "react-router-dom";

  describe("<CertificateHtmlLink", () => {
    it("should link to dynamic HTML certificate page URL on click event", () => {
      // Arrange:
      const history = createMemoryHistory({ initialEntries: ["/"] });

      // Act:
      const { getByText } = render(
        <Router history={history}>
          <CertificateHtmlLink to="/certificate/123" />
        </Router>
      );

      // Assert:
      expect(history.location.pathname).toBe("/");
      fireEvent.click(getByText("View HTML version"));
      expect(history.location.pathname).toBe("/certificate/123");
    });
  });
  ```


path: zk/Rules_for_operations_on_like_and_unlike_terms.md
sortable_path: zkRules_for_operations_on_like_and_unlike_terms.md
title: Addition
lead: ### Like terms
checksum: b14e083fb61dec1ce1b85a9981265684b782ee062018ec7292d83734b7bd23c5
created: 2024-03-30 09:03:20.970920754+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["prealgebra"]}
body:
  ### Like terms

  > Sum the absolute values and add the negative sign afterwards.

  $$
  \\begin{split}
  -4 + -3
  \\ = 4 + 3
  \\ = -7
  \\end{split}
  $$

  ### Unlike terms

  > Subtract smaller from larger amount and then affix the sign of the larger
  > amount to the sum.

  #### Negative plus positive

  $$
  \\begin{split}
  -8 + 5
  \\ = 8 - 5
  \\ = 3
  \\ = -3
  \\end{split}
  $$

  #### Positive plus negative

  $$
  \\begin{split}
  4 + -1
  \\ = 4 - 1
  \\ = 3
  \\end{split}
  $$

  ## Subtraction

  ### Like terms

  > Turn the operator and second negative into a plus sign and execute as an
  > addition.

  $$
  \\begin{split}
  -4 - -3 =
  \\ = -4 + 3
  \\ = -1
  \\end{split}
  $$

  ### Unlike terms

  #### Positive subtract negative

  > Turn the negative after the operator to a positive. (Same as previous.)
  >
  > $$
  > \\begin{split}
  > 2 - -3 =
  > \\ = 2 + 3
  > \\ = 5
  > \\end{split}
  > $$

  #### Negative subtract positive

  > Start at the negative value and count backwards on the number-line

  $$
  -2 - 3 = -5
  $$

  ## Multiplication

  ### Like terms

  > The product of two negative numbers will always be a positive number.

  $$
  -15 \cdot -3 = 45
  $$

  ### Unlike terms

  > The product of a positive and a negative number will always be a negative
  > number.

  $$
  -3 \cdot 5 = -15
  $$

  ## Division

  **Division follows the same rules as multiplication.**

  ### Like terms

  > The quotient of two negative numbers will always be a positive number.

  $$
  -15 / -3 = 5
  $$

  ### Unlike terms

  > The quotient of a positive and a negative number will always be a negative
  > number.

  $$
  -15 / 3 = -5
  $$

raw_content:
  ---
  tags:
    - prealgebra
  ---

  ## Addition

  ### Like terms

  > Sum the absolute values and add the negative sign afterwards.

  $$
  \\begin{split}
  -4 + -3
  \\ = 4 + 3
  \\ = -7
  \\end{split}
  $$

  ### Unlike terms

  > Subtract smaller from larger amount and then affix the sign of the larger
  > amount to the sum.

  #### Negative plus positive

  $$
  \\begin{split}
  -8 + 5
  \\ = 8 - 5
  \\ = 3
  \\ = -3
  \\end{split}
  $$

  #### Positive plus negative

  $$
  \\begin{split}
  4 + -1
  \\ = 4 - 1
  \\ = 3
  \\end{split}
  $$

  ## Subtraction

  ### Like terms

  > Turn the operator and second negative into a plus sign and execute as an
  > addition.

  $$
  \\begin{split}
  -4 - -3 =
  \\ = -4 + 3
  \\ = -1
  \\end{split}
  $$

  ### Unlike terms

  #### Positive subtract negative

  > Turn the negative after the operator to a positive. (Same as previous.)
  >
  > $$
  > \\begin{split}
  > 2 - -3 =
  > \\ = 2 + 3
  > \\ = 5
  > \\end{split}
  > $$

  #### Negative subtract positive

  > Start at the negative value and count backwards on the number-line

  $$
  -2 - 3 = -5
  $$

  ## Multiplication

  ### Like terms

  > The product of two negative numbers will always be a positive number.

  $$
  -15 \cdot -3 = 45
  $$

  ### Unlike terms

  > The product of a positive and a negative number will always be a negative
  > number.

  $$
  -3 \cdot 5 = -15
  $$

  ## Division

  **Division follows the same rules as multiplication.**

  ### Like terms

  > The quotient of two negative numbers will always be a positive number.

  $$
  -15 / -3 = 5
  $$

  ### Unlike terms

  > The quotient of a positive and a negative number will always be a negative
  > number.

  $$
  -15 / 3 = -5
  $$


path: zk/S3.md
sortable_path: zkS3.md
title: S3
checksum: 71de289fb1009995825d1050865f4e550269258bd276f23ef7e28099c78b7165
created: 2024-03-30 09:03:20.973978897+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS"]}
lead:
  You can think of S3 as an external mounted harddrive for storing raw binary data
  (images, soundfiles, documents etc).

body:
  You can think of S3 as an external mounted harddrive for storing raw binary data
  (images, soundfiles, documents etc).

  Your use of the S3 service is divided up into **buckets**. Buckets contain files
  and resources. These are just resource names in an online container, the data
  doesn't have any structure beyond that.

  The primary use of S3 is to store resources that an application needs and/or to
  facilitate the uploading and downloading of resources to and from an
  application.

  You can set access and authentication conditions for buckets, making the data
  public or restricted.

raw_content:
  ---
  tags: [AWS]
  ---

  # S3

  You can think of S3 as an external mounted harddrive for storing raw binary data
  (images, soundfiles, documents etc).

  Your use of the S3 service is divided up into **buckets**. Buckets contain files
  and resources. These are just resource names in an online container, the data
  doesn't have any structure beyond that.

  The primary use of S3 is to store resources that an application needs and/or to
  facilitate the uploading and downloading of resources to and from an
  application.

  You can set access and authentication conditions for buckets, making the data
  public or restricted.


path: zk/SAM.md
sortable_path: zkSAM.md
title: AWS SAM
checksum: f8c24e34ef80334d12ece3ae1f8ab00756aa1fade97ebc1202b2e78096913b62
created: 2024-03-30 09:03:20.980092239+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS"]}
lead:
  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

body:
  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

  The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
  SAM syntax gets transformed into CloudFormation during the deployment process.
  (CloudFormation is a broader and more robust AWS tool for large, highly
  scaleable infrastructures).

  ## Key features of SAM

  - Single deployment configuration
  - Integration with development tools
  - Local testing and debugging
  - Built on AWS CloudFormation

  ## Main technologies required

  ### Docker

  Whilst SAM can be used to create a deployable file for AWS it can also be run as
  a container for local development with Docker.

  ### AWS CLI

  This is installed using Python and allows you to interact directly with AWS via
  the command-line.

  ### AWS SAM CLI

  See
  [https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)

  ## Setting up credentials for the AWS CLI

  You require an access key for the given
  [IAM user](zk/AWS_User_management_and_roles.md#iam). You should create an IAM
  account specific to the project with bounded permissions.

  ```
  aws configure
  AWS Access Key ID [None]: AK*******
  AWS Secret Access Key [None]: ukp******
  Default region name [None]:
  Default output format [None]:
  ```

  This information can be found in the Security Credentials section of the given
  [IAM](zk/AWS_User_management_and_roles.md#iam) user:

  ![](/img/access-key-aws.png)

  ### Switching between credentials

  You should set up a different IAM user for each project.

  You can do this with:

  ```sh
  aws configure --profile <profile-name>
  ```

  This will then ask you to add the credentials for the user.

  You can switch between different credentials for the user as follows:

  ```sh
  AWS_PROFILE=<profile-name> sam build

  ```

  ## Starting a SAM project

  First create a directory for your project which will serve as the repository:

  ```sh
  mkdir aws-sam-learning
  cd aws-sam-learning
  ```

  Then we can use the `sam` cli to bootstrap the project:

  ```sh
  sam init --runtime nodejs16.x
  ```

  We can just click through and accept the basic HelloWorld Lambda.

  This will create the Lambda as well as an API Gateway trigger URL.

  ### `template.yaml`

  This is autogenerated and details the main constituents of the project. There
  are lots of fields but the most important are the following:

  ```yaml
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
  ```

  This details the location of the [handler function](/Lambda_handler_function.md)
  which is contained at the path `hello-world/app.js`:

  ```js
  exports.lambdaHandler = async (event, context) => {
    try {
      // const ret = await axios(url);
      response = {
        statusCode: 200,
        body: JSON.stringify({
          message: "hello world",
          // location: ret.data.trim()
        }),
      };
    } catch (err) {
      console.log(err);
      return err;
    }

    return response;
  };
  ```

  It also lists the `get` event that we can use to call API Gateway and trigger
  the Lambda.

  The full template is below:

  ![](/img/sam-template-yaml.png)

  ## Adding our own code

  We will create our own function and API Gateway trigger.

  We will place our function after the existing `HelloWorldFunction`

  ```yaml
  ClockFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: clock/
      Handler: handler.clock
      Runtime: nodejs16.x
    Events:
      ClockApi:
        Type: Api
        Properties:
          Path: /clock
          Method: get
  ```

  We can test the syntax with:

  ```sh
  sam validate
  ```

  Just like with `HelloWorld`, we will create a directory for this function:
  `clock` and we will initialise it as an `npm` project.

  ```sh
  mkdir clock
  cd clock
  npm init
  ```

  We will use `handler.js` as our root, handler function.

  We have said in the template file that our `Handler: handler.clock`, therefore
  the main function in the `handler` module should be `clock`:

  ```js
  const moment = require("moment");

  exports.clock = async (event) => {
    console.log("Clock function run");
    const message = moment().format();
    const response = {
      statusCode: 200,
      body: JSON.stringify(message),
    };
    return response;
  };
  ```

  The directory structure is as follows:

  ![](/_img/sam-directory.png)

  When we call the API Gateway path `/clock` with `GET`, our function will be
  triggered.

  ## Deploying the project

  We will now deploy our project to AWS from the local environment.

  The process is as follows:

  1. Build
  2. Package
  3. Deploy

  ### Build

  We need to install the runtime dependencies for the function. We do this by
  running `sam build`. This ignores test files and development dependencies and
  installs the project dependencies and source files to a temporary subdirectory.

  ![](/img/sam-build.png)

  The build directory is `.aws-sam/build/`. There will be a subdirectory for each
  of our files.

  ### Package

  As noted, CloudFront handles the deployment of the application. It can only
  receive one file as an input. The packaging process consists in creating that
  single file.

  The packaging proces will first archive all of the project artefacts into a zip
  file and then upload that to [S3](zk/AWS_S3.md). A reference to this S3 entity
  is then provided to CloudFormation.

  ![](/img/s3-package-again.svg)

  The command is as follows:

  ```sh
  sam package
    --template-file template.yaml
    --output-template-file pkg.yml
    --region eu-west-1
  ```

  This will automatically create a hashed bucket name for you in S3 (I have tried
  to add my own naming but it doesn't comply.)

  ### Local development with Docker

  In order to work with your application locally without actually sending requests
  to AWS and using credit, you can run a local instance.

  See [Local AWS Development with SAM](zk/Local_AWS_development_with_SAM.md).

  ### Deploy

  Once you have packaged the app you can deploy with `sam deploy --guided`. This
  will talk you through the defaults and will deploy the package to
  CloudFormation. In CloudFormation each individual project is called a **stack**.

  If we then go to Cloud Formation we will see the deployed application.

  ![](/img/cloud-formation-stack.png)

  ## Call the endpoint

  If we now go to the Lambda console, we will see our function listed, and the API
  Gateway endpoint under `triggers`:

  ![](/img/gateway-trigger.png)

  We can then call this from Postman to check everything is working as it should:

  ![](/img/postman-aws-output.png)

raw_content:
  ---
  tags: [AWS]
  ---

  # AWS SAM

  SAM stands for **serverless application model**. It is a framework developed by
  AWS to simplify the process of building, deploying and managing serverless
  applications. It provides a concise syntax for defining the components of a
  serverless application, such as
  [Lambda functions](zk/Lambda_programming_model.md),
  [API gateway](/zk/AWS_API_Gateway.md) and database tables.

  The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
  SAM syntax gets transformed into CloudFormation during the deployment process.
  (CloudFormation is a broader and more robust AWS tool for large, highly
  scaleable infrastructures).

  ## Key features of SAM

  - Single deployment configuration
  - Integration with development tools
  - Local testing and debugging
  - Built on AWS CloudFormation

  ## Main technologies required

  ### Docker

  Whilst SAM can be used to create a deployable file for AWS it can also be run as
  a container for local development with Docker.

  ### AWS CLI

  This is installed using Python and allows you to interact directly with AWS via
  the command-line.

  ### AWS SAM CLI

  See
  [https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)

  ## Setting up credentials for the AWS CLI

  You require an access key for the given
  [IAM user](zk/AWS_User_management_and_roles.md#iam). You should create an IAM
  account specific to the project with bounded permissions.

  ```
  aws configure
  AWS Access Key ID [None]: AK*******
  AWS Secret Access Key [None]: ukp******
  Default region name [None]:
  Default output format [None]:
  ```

  This information can be found in the Security Credentials section of the given
  [IAM](zk/AWS_User_management_and_roles.md#iam) user:

  ![](/img/access-key-aws.png)

  ### Switching between credentials

  You should set up a different IAM user for each project.

  You can do this with:

  ```sh
  aws configure --profile <profile-name>
  ```

  This will then ask you to add the credentials for the user.

  You can switch between different credentials for the user as follows:

  ```sh
  AWS_PROFILE=<profile-name> sam build

  ```

  ## Starting a SAM project

  First create a directory for your project which will serve as the repository:

  ```sh
  mkdir aws-sam-learning
  cd aws-sam-learning
  ```

  Then we can use the `sam` cli to bootstrap the project:

  ```sh
  sam init --runtime nodejs16.x
  ```

  We can just click through and accept the basic HelloWorld Lambda.

  This will create the Lambda as well as an API Gateway trigger URL.

  ### `template.yaml`

  This is autogenerated and details the main constituents of the project. There
  are lots of fields but the most important are the following:

  ```yaml
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
  ```

  This details the location of the [handler function](/Lambda_handler_function.md)
  which is contained at the path `hello-world/app.js`:

  ```js
  exports.lambdaHandler = async (event, context) => {
    try {
      // const ret = await axios(url);
      response = {
        statusCode: 200,
        body: JSON.stringify({
          message: "hello world",
          // location: ret.data.trim()
        }),
      };
    } catch (err) {
      console.log(err);
      return err;
    }

    return response;
  };
  ```

  It also lists the `get` event that we can use to call API Gateway and trigger
  the Lambda.

  The full template is below:

  ![](/img/sam-template-yaml.png)

  ## Adding our own code

  We will create our own function and API Gateway trigger.

  We will place our function after the existing `HelloWorldFunction`

  ```yaml
  ClockFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: clock/
      Handler: handler.clock
      Runtime: nodejs16.x
    Events:
      ClockApi:
        Type: Api
        Properties:
          Path: /clock
          Method: get
  ```

  We can test the syntax with:

  ```sh
  sam validate
  ```

  Just like with `HelloWorld`, we will create a directory for this function:
  `clock` and we will initialise it as an `npm` project.

  ```sh
  mkdir clock
  cd clock
  npm init
  ```

  We will use `handler.js` as our root, handler function.

  We have said in the template file that our `Handler: handler.clock`, therefore
  the main function in the `handler` module should be `clock`:

  ```js
  const moment = require("moment");

  exports.clock = async (event) => {
    console.log("Clock function run");
    const message = moment().format();
    const response = {
      statusCode: 200,
      body: JSON.stringify(message),
    };
    return response;
  };
  ```

  The directory structure is as follows:

  ![](/_img/sam-directory.png)

  When we call the API Gateway path `/clock` with `GET`, our function will be
  triggered.

  ## Deploying the project

  We will now deploy our project to AWS from the local environment.

  The process is as follows:

  1. Build
  2. Package
  3. Deploy

  ### Build

  We need to install the runtime dependencies for the function. We do this by
  running `sam build`. This ignores test files and development dependencies and
  installs the project dependencies and source files to a temporary subdirectory.

  ![](/img/sam-build.png)

  The build directory is `.aws-sam/build/`. There will be a subdirectory for each
  of our files.

  ### Package

  As noted, CloudFront handles the deployment of the application. It can only
  receive one file as an input. The packaging process consists in creating that
  single file.

  The packaging proces will first archive all of the project artefacts into a zip
  file and then upload that to [S3](zk/AWS_S3.md). A reference to this S3 entity
  is then provided to CloudFormation.

  ![](/img/s3-package-again.svg)

  The command is as follows:

  ```sh
  sam package
    --template-file template.yaml
    --output-template-file pkg.yml
    --region eu-west-1
  ```

  This will automatically create a hashed bucket name for you in S3 (I have tried
  to add my own naming but it doesn't comply.)

  ### Local development with Docker

  In order to work with your application locally without actually sending requests
  to AWS and using credit, you can run a local instance.

  See [Local AWS Development with SAM](zk/Local_AWS_development_with_SAM.md).

  ### Deploy

  Once you have packaged the app you can deploy with `sam deploy --guided`. This
  will talk you through the defaults and will deploy the package to
  CloudFormation. In CloudFormation each individual project is called a **stack**.

  If we then go to Cloud Formation we will see the deployed application.

  ![](/img/cloud-formation-stack.png)

  ## Call the endpoint

  If we now go to the Lambda console, we will see our function listed, and the API
  Gateway endpoint under `triggers`:

  ![](/img/gateway-trigger.png)

  We can then call this from Postman to check everything is working as it should:

  ![](/img/postman-aws-output.png)


path: zk/Schema_Definition_Language.md
sortable_path: zkSchema_Definition_Language.md
title: Schema Definition Language
lead: SDL is the formal name for the syntax of GraphQL schemas.
checksum: c50d5b10c7f9a915e1d4d5d9bb67ef337b59f126f97bfda5c6bfeba74d25ac1c
created: 2024-03-30 09:03:21.043334122+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["graphql"]}
body:
  SDL is the formal name for the syntax of GraphQL schemas.

  ## Types

  A schema is a collection of object types that contain fields. Each field has a
  type of its own. A field's type can be a primitive/scalar value (such as an
  `Int` or a `String`), or it can be another object type (just like a custom type
  in TS).

  A schema's type can be non-nullable which is to say, a required field. We
  indicate this with `!`.

  A type for a field can be a collection/array of a given type.

  The following example indicates these properties:

  ```gql
  type Person {
    age: Int
    name: String
    pets: [Pet]!
  }

  type Pet {
    species: String
    name: String
    age: Int
  }
  ```

  ## Queries

  A query is also a schema type but of a special sort.

  > The fields of this type are entry points into the rest of the schema. These
  > are the top-level fields that the client can query for.

  For example if we had this type:

  ```graphql
  type Track {
    id: ID!
      author: Author!
    thumbnail: String
    length: Int
    modulesCount: Int
  }
  ```

  We could define a type to access a give `Track` as follows:

  ```graphql
  type Query {
    tracksForHomePage: [Track!]!
  }
  ```

  Then use this type as the basis for a query:

  ```

  ```

  ## Descriptions

  Descriptions are comments that allow you to document your Schema

  Single line:

  ```gql
  "Single line comment"
  ```

  ```gql
  """
  Multi
  line
  comment
  """
  ```

raw_content:
  ---
  tags: [graphql]
  ---

  # Schema Definition Language

  SDL is the formal name for the syntax of GraphQL schemas.

  ## Types

  A schema is a collection of object types that contain fields. Each field has a
  type of its own. A field's type can be a primitive/scalar value (such as an
  `Int` or a `String`), or it can be another object type (just like a custom type
  in TS).

  A schema's type can be non-nullable which is to say, a required field. We
  indicate this with `!`.

  A type for a field can be a collection/array of a given type.

  The following example indicates these properties:

  ```gql
  type Person {
    age: Int
    name: String
    pets: [Pet]!
  }

  type Pet {
    species: String
    name: String
    age: Int
  }
  ```

  ## Queries

  A query is also a schema type but of a special sort.

  > The fields of this type are entry points into the rest of the schema. These
  > are the top-level fields that the client can query for.

  For example if we had this type:

  ```graphql
  type Track {
    id: ID!
      author: Author!
    thumbnail: String
    length: Int
    modulesCount: Int
  }
  ```

  We could define a type to access a give `Track` as follows:

  ```graphql
  type Query {
    tracksForHomePage: [Track!]!
  }
  ```

  Then use this type as the basis for a query:

  ```

  ```

  ## Descriptions

  Descriptions are comments that allow you to document your Schema

  Single line:

  ```gql
  "Single line comment"
  ```

  ```gql
  """
  Multi
  line
  comment
  """
  ```


path: zk/Secrets_or_env_vars.md
sortable_path: zkSecrets_or_env_vars.md
title: Secrets or environment variables?
checksum: 5dbb25aea37698bb6cf861e39dfd15ee9823b0e0e928f76e9d1d4e3899538a9b
created: 2024-03-30 09:03:21.04733042+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["AWS","aws-lambda"]}
lead:
  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

body:
  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

  General recommendations suggest using AWS Secrets Manager for storing sensitive
  data like API keys and passwords, due to its enhanced security features. For
  less sensitive, non-critical data such as feature flags or environment-specific
  URLs, environment variables are often adequate. Cost-conscious users who don't
  need advanced features may find environment variables more economical.
  Ultimately, the best choice depends on your specific requirements and
  limitations.

raw_content:
  ---
  tags: [AWS, aws-lambda]
  ---

  # Secrets or environment variables?

  Choosing between environment variables and AWS Secrets Manager hinges on factors
  such as use case, security needs, and the data type. Environment variables are
  easier to use, free, and offer fast access but are less secure and lack features
  like versioning. On the other hand, AWS Secrets Manager provides robust security
  through encryption, access control, audit trails, and supports secret versioning
  and rotation. However, it comes with additional costs and can introduce latency
  and rate limits.

  General recommendations suggest using AWS Secrets Manager for storing sensitive
  data like API keys and passwords, due to its enhanced security features. For
  less sensitive, non-critical data such as feature flags or environment-specific
  URLs, environment variables are often adequate. Cost-conscious users who don't
  need advanced features may find environment variables more economical.
  Ultimately, the best choice depends on your specific requirements and
  limitations.


path: zk/Semantic_versioning.md
sortable_path: zkSemantic_versioning.md
title: Semantic versioning
lead:
  ```
  3.4.1 === major.minor.patch
  ```

checksum: 594b1e9ce9125afba02b6d41efe4af9a53aff06bff3ab7739bc2e89e65f6d664
created: 2024-03-30 09:03:21.052315622+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":[]}
body:
  ```
  3.4.1 === major.minor.patch
  ```

  - Major

    - New feature which may potentially cause breaking changes to applications
      dependent on the previous major version.

  - Minor

    - New features that do not break the existing API

  - Patch

    - Bug fixes for the current minor version

  ## Glob patterns for versioning

  ### Caret

  Interested in any version so long as the major version remains at $n$. E.g if we
  are at `^4.2.1` and we upgrade, we are ok with `4.5.3` or `4.8.2`. We are not
  bothered about the minor or patch version.

  This is equivalent to `4.x`

  ### Tilde

  Interested in any patch version within set major and minor parameters. For
  example `~1.8.3` means you don't mind any patch version so long as it is a patch
  for `1.8`. This is equivalent to `1.8.x`.

  ### No tilde or caret

  Use the _exact_ version specified

raw_content:
  ---
  tags: []
  ---

  # Semantic versioning

  ```
  3.4.1 === major.minor.patch
  ```

  - Major

    - New feature which may potentially cause breaking changes to applications
      dependent on the previous major version.

  - Minor

    - New features that do not break the existing API

  - Patch

    - Bug fixes for the current minor version

  ## Glob patterns for versioning

  ### Caret

  Interested in any version so long as the major version remains at $n$. E.g if we
  are at `^4.2.1` and we upgrade, we are ok with `4.5.3` or `4.8.2`. We are not
  bothered about the minor or patch version.

  This is equivalent to `4.x`

  ### Tilde

  Interested in any patch version within set major and minor parameters. For
  example `~1.8.3` means you don't mind any patch version so long as it is a patch
  for `1.8`. This is equivalent to `1.8.x`.

  ### No tilde or caret

  Use the _exact_ version specified


path: zk/Sets_in_Python.md
sortable_path: zkSets_in_Python.md
title: Sets in Python
checksum: 766c8d1f8a0736bf3d4e5e1f15ba881fe068dd8f6f2b0d8888c184a25608328a
created: 2024-03-30 09:03:21.057134408+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["python","data-structures"]}
lead:
  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

body:
  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

  > Sets are denoted with `{...}`

  ## Basic usage

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print(basket)  # show that duplicates have been removed
  print(len(basket))
  # {'apple', 'pear', 'banana', 'orange'}
  # 4
  ```

  ## Looping through sets

  ```python
  for item in basket:
      print(item)

  """
  apple
  pear
  banana
  orange
  """
  ```

  ## Check for membership

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print('apple' in basket)
  # True
  ```

  ## Remove items from set

  > `remove` will raise an error if the specified item does not exist, `discard`
  > will not

  ```python
  basket.remove('apple')
  basket.discard('apricot')
  print(basket)
  # {'pear', 'banana', 'orange'}

  basket.clear()
  print(basket)
  #set

  ```

  ## Add items to a set

  ```python
  basket.add('apricot')
  print(basket)
  # {'apricot', 'pear', 'banana', 'orange'}
  ```

  ## Start with empty set

  To declare an empty set you cannot just do:

  ```py
  my_set = {}
  ```

  You have to use a constructor:

  ```py
  my_set = set()
  ```

  ## Apply unions and intersections

  ```python
  s1 = {'apple', 'orange', 'banana'}
  s2 = {'grapefruit', 'lime', 'banana'}
  print('Union:', s1 | s2)
  # Union: {'apple', 'orange', 'grapefruit', 'lime', 'banana'}

  print('Intersection:', s1 & s2)
  # Intersection: {'banana'}


  print('Difference:', s1 - s2)
  # Difference: {'orange', 'apple'}

  print('Symmetric Difference:', s1 ^ s2)
  #Symmetric Difference: {'apple', 'orange', 'grapefruit', 'lime'}

  ```

raw_content:
  ---
  tags: [python, data-structures]
  ---

  # Sets in Python

  - They are **unordered**
  - You can increase/decrease their length by adding/removing new members
  - They **do not allow duplicate members**
  - **Can only hold immutable objects**

  > Sets are denoted with `{...}`

  ## Basic usage

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print(basket)  # show that duplicates have been removed
  print(len(basket))
  # {'apple', 'pear', 'banana', 'orange'}
  # 4
  ```

  ## Looping through sets

  ```python
  for item in basket:
      print(item)

  """
  apple
  pear
  banana
  orange
  """
  ```

  ## Check for membership

  ```python
  basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
  print('apple' in basket)
  # True
  ```

  ## Remove items from set

  > `remove` will raise an error if the specified item does not exist, `discard`
  > will not

  ```python
  basket.remove('apple')
  basket.discard('apricot')
  print(basket)
  # {'pear', 'banana', 'orange'}

  basket.clear()
  print(basket)
  #set

  ```

  ## Add items to a set

  ```python
  basket.add('apricot')
  print(basket)
  # {'apricot', 'pear', 'banana', 'orange'}
  ```

  ## Start with empty set

  To declare an empty set you cannot just do:

  ```py
  my_set = {}
  ```

  You have to use a constructor:

  ```py
  my_set = set()
  ```

  ## Apply unions and intersections

  ```python
  s1 = {'apple', 'orange', 'banana'}
  s2 = {'grapefruit', 'lime', 'banana'}
  print('Union:', s1 | s2)
  # Union: {'apple', 'orange', 'grapefruit', 'lime', 'banana'}

  print('Intersection:', s1 & s2)
  # Intersection: {'banana'}


  print('Difference:', s1 - s2)
  # Difference: {'orange', 'apple'}

  print('Symmetric Difference:', s1 ^ s2)
  #Symmetric Difference: {'apple', 'orange', 'grapefruit', 'lime'}

  ```


path: zk/Setup_configuration.md
sortable_path: zkSetup_configuration.md
title: Setup and configuration
lead: ## Installation and configuration
checksum: 7ad962fc516dcea03815580140ae449dfaeb4c74b9e330cc4b8199af5454edf1
created: 2024-03-30 09:03:21.062227848+00:00
modified: 2024-03-27 10:45:52.506858751+00:00
metadata: {"tags":["typescript"]}
body:
  ## Installation and configuration

  TypeScript offers custom installations for most modern JS-based frameworks
  including Webpack, React.js and Vue.js. The instructions below cover minimal TS
  set-up outside of a specific framework. TypeScript adds an additional step to
  any build process since your code must compile to JS before any bundling and
  transpilation can occur.

  ## Installation

  ```
  mkdir typescript-project
  cd typescript-project
  npm i typescript --save-dev
  ```

  ## Initialise project

  ```
  npx tsc --init
  ```

  ## Basic configuration

  ```json
  "compilerOptions": {
  	"target" : "es2020", //es2015 for prod
  	"module" : "es2020",
    	"allowJs": true,
    	"checkJs": true,
    	"strict": true,
    	"esModuleInterop": true
  }
  ```

  ### Specify output paths (for production code)

  ```json
  "compilerOptions": {
  	...
  	"outDir": "dist",
  	"sourceMap": true,
  }
  ```

  ### Compile-time commands

  ```
  tsc --noEmit
  ```

  ```
  tsc --noEmit --watch
  ```

  ## Global requirements

  ```
  npm install -g typescript
  npm install -g ts-node
  ```

  `ts-node` allows you to run TS files the way you would with standard JS, i.e.
  `node [filename]`, you just use `ts-node filename` .

  This is a convenience that saves you compiling from TS → JS and then running
  Node against the compiled JS. Which is useful for debugging and checking values
  as you work.

  ## Imports and exports

  You may wish to define your custom types outside of their application, for
  instance in a `/types/` directory. The custom type or types can then be imported
  using standard ES6 imports:

  ```tsx
  export type Article = {
  		price: number,
  }

  export type AnotherType = {
  ...
  }
  ```

  ```tsx
  import { Article, AnotherType } from "./types/allTypes.js";
  import Article from "./types/allTypes.js";
  ```

  TypeScript also provides a specific import keyword `type` so that you can
  distinguish type imports from other module imports. This is handy when you have
  multiple components in the one file:

  ```tsx
  import type { Article } from "./types/allTypes.js";
  ```

raw_content:
  ---
  tags:
    - typescript
  ---

  # Setup and configuration

  ## Installation and configuration

  TypeScript offers custom installations for most modern JS-based frameworks
  including Webpack, React.js and Vue.js. The instructions below cover minimal TS
  set-up outside of a specific framework. TypeScript adds an additional step to
  any build process since your code must compile to JS before any bundling and
  transpilation can occur.

  ## Installation

  ```
  mkdir typescript-project
  cd typescript-project
  npm i typescript --save-dev
  ```

  ## Initialise project

  ```
  npx tsc --init
  ```

  ## Basic configuration

  ```json
  "compilerOptions": {
  	"target" : "es2020", //es2015 for prod
  	"module" : "es2020",
    	"allowJs": true,
    	"checkJs": true,
    	"strict": true,
    	"esModuleInterop": true
  }
  ```

  ### Specify output paths (for production code)

  ```json
  "compilerOptions": {
  	...
  	"outDir": "dist",
  	"sourceMap": true,
  }
  ```

  ### Compile-time commands

  ```
  tsc --noEmit
  ```

  ```
  tsc --noEmit --watch
  ```

  ## Global requirements

  ```
  npm install -g typescript
  npm install -g ts-node
  ```

  `ts-node` allows you to run TS files the way you would with standard JS, i.e.
  `node [filename]`, you just use `ts-node filename` .

  This is a convenience that saves you compiling from TS → JS and then running
  Node against the compiled JS. Which is useful for debugging and checking values
  as you work.

  ## Imports and exports

  You may wish to define your custom types outside of their application, for
  instance in a `/types/` directory. The custom type or types can then be imported
  using standard ES6 imports:

  ```tsx
  export type Article = {
  		price: number,
  }

  export type AnotherType = {
  ...
  }
  ```

  ```tsx
  import { Article, AnotherType } from "./types/allTypes.js";
  import Article from "./types/allTypes.js";
  ```

  TypeScript also provides a specific import keyword `type` so that you can
  distinguish type imports from other module imports. This is handy when you have
  multiple components in the one file:

  ```tsx
  import type { Article } from "./types/allTypes.js";
  ```


