<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Adam Hawley</title>
    <link>https://adamjhawley.com/</link>
    <description>Recent content on Adam Hawley</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Sun, 10 Sep 2023 11:28:57 +0300</lastBuildDate><atom:link href="https://adamjhawley.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How Intel Server CPUs Save Power - Intro to C-states</title>
      <link>https://adamjhawley.com/post/2023-09-10-intro-to-cstates/</link>
      <pubDate>Sun, 10 Sep 2023 11:28:57 +0300</pubDate>
      
      <guid>https://adamjhawley.com/post/2023-09-10-intro-to-cstates/</guid>
      
      <description>&lt;p&gt;Note: this post describes how C-states work on Intel server CPUs. C-states are often similar on alternative platforms but the specifics of each state differ. However, the basic concept of using C-states for power management is common to all platforms, including client systems.&lt;/p&gt;
&lt;h2 id=&#34;what-are-c-states&#34;&gt;What are C-states?&lt;/h2&gt;
&lt;p&gt;C-states represent different power states for CPU cores, each state consumes different amounts of power and has slightly different behaviour. They are used to save energy while the CPU is powered but idle.&lt;/p&gt;
&lt;p&gt;As a human analogy, think of C-states as different stages of relaxation; going from a quick sit-down all the way to a deep meditation.&lt;/p&gt;
&lt;p&gt;As with humans, the deeper the state a CPU is in, the longer it will take to resume working/respond to interruptions. This is an important aspect of CPU power management; balancing power savings from entering deeper states without increasing the time it takes to continue operating.&lt;/p&gt;
&lt;h2 id=&#34;differences-between-hardware-and-software-c-states&#34;&gt;Differences between “hardware” and “software” C-states&lt;/h2&gt;
&lt;p&gt;It is important to be aware that there are two types of C-state and both are often used in isolation and simply called “C-states”.&lt;/p&gt;
&lt;p&gt;Software C-states are commonly also referred to as “Requested C-states” or “Logical C-states”. This is because these are the C-states which can be requested by the operating system. While hardware C-states reflect the actual state of a CPU. Notation varies slightly between hardware and software C-states but understanding how they connect is usually intuitive.&lt;/p&gt;
&lt;p&gt;For example, the OS can request that the CPU goes into the hardware state “CC1”, by referencing the software state “C1”.&lt;/p&gt;
&lt;h2 id=&#34;how-are-c-states-used-to-save-power&#34;&gt;How are C-states used to save power?&lt;/h2&gt;
&lt;p&gt;When the operating system has no runnable tasks, it can maximise on the opportunity to save power. It first estimates which software C-state will be the most suitable to request based on a number of factors such as how long it thinks the system will be idle for. Then it uses the &lt;code&gt;mwait&lt;/code&gt; instruction to hint and request that C-state to the CPU. It is then up to the processor to determine exactly which hardware C-state it will enter.&lt;/p&gt;
&lt;h2 id=&#34;what-are-the-different-c-states&#34;&gt;What are the different C-states?&lt;/h2&gt;
&lt;p&gt;Going from “shallowest” to “deepest” (i.e. lowest to highest power saving), here are examples of commonly used hardware C-states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This list is not exhaustive of all C-states and many platforms support many other hardware C-states. However, those listed below are extremely widely supported and used in production systems working today.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;CC0 - The busy state, indicates that the CPU is currently operating.&lt;/li&gt;
&lt;li&gt;CC1 - The CPU begins “core clock gating”. In CC1, the core has stopped executing but the state is preserved. This means that to return to normal operation, the core just has to stop core gating.&lt;/li&gt;
&lt;li&gt;CC1e - Known as “Enhanced C1”. In addition to the clock gaiting involved in CC1, there is also a suggestion to drop the core voltage. This means that C1e has a similar wake-up latency to C1 but will operate at a slightly lower frequency after waking up, while the voltage is restored. Note: the reason it is only a &lt;em&gt;hint&lt;/em&gt;, is that the CPU will generally only reduce the voltage if every core has entered C1e.&lt;/li&gt;
&lt;li&gt;CC6 - Rather than clock gating, in CC6, the CPU begins “power gating” which means that the core voltage will be reduced to 0V. Cores in CC6 can take up to 10 times longer to wake from idle than the previously-mentioned C-states. This is because when the core reduces the voltage to 0V, it has to flush caches and other state-saving components. This means that the state of the core has to be saved elsewhere. Therefore, when the core is awoken, it will have to restore its operating state from nothing. This process of restoring the state does not apply to any of the previous C-states.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the C-states above are core C-states, which means that they affect the power consumption at a core level. However, there are C-states which represent a power state of larger scopes such as at the package level (e.g. PC6 - package C6).&lt;/p&gt;
&lt;h2 id=&#34;wake-latency&#34;&gt;Wake Latency&lt;/h2&gt;
&lt;p&gt;As mentioned above, going to deeper states means saving power. But this comes at a cost. That cost is called “Wake Latency”. Wake latency is the time it takes for the CPU to wake from a given C-state and continue operating.&lt;/p&gt;
&lt;p&gt;To measure wake latency, at Intel, I work on a free and open-source tool walled ‘&lt;a href=&#34;github.com/intel/wult&#34;&gt;wult&lt;/a&gt;’ - Wake Up Latency Tracer. ‘wult’ tests wake latencies of CPUs with the following process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set a timer in the future - the CPU “alarm clock”.&lt;/li&gt;
&lt;li&gt;Tell the CPU to sleep.&lt;/li&gt;
&lt;li&gt;When the timer expires, trigger an interrupt which wakes the CPU.&lt;/li&gt;
&lt;li&gt;As soon as the CPU is awake, read the current time and calculate the difference between the timer triggering and the current time. That’s the wake latency!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information, the &lt;a href=&#34;https://intel.github.io/wult/pages/how-it-works.html&#34;&gt;wult documentation&lt;/a&gt; describes in detail how the process works and the selection of methods that can be used to implement the method outlined above.&lt;/p&gt;
&lt;h2 id=&#34;how-can-i-modify-c-states-on-linux&#34;&gt;How can I modify C-states on Linux?&lt;/h2&gt;
&lt;p&gt;Another free and open-source tool I have contributed to is called ‘&lt;a href=&#34;https://github.com/intel/pepc&#34;&gt;pepc&lt;/a&gt;’ - Power, Energy &amp;amp; Performance Configurator. On Linux, this tool can be used to easily enable and disable C-states through a CLI.&lt;/p&gt;
&lt;h2 id=&#34;further-reading&#34;&gt;Further reading&lt;/h2&gt;
&lt;p&gt;If you would like to learn more about server CPU power management, I strongly recommend the freely available book &lt;a href=&#34;https://link.springer.com/book/10.1007/978-1-4302-6638-9&#34;&gt;Energy Efficient Servers by Corey Gough, Ian Steiner &amp;amp; Winston Saunders&lt;/a&gt;. This book was given to me when I started at Intel and it taught me a lot as a great introduction to server CPU power management.&lt;/p&gt;
&lt;p&gt;Additionally, in case you are interested in Linux specifics, you can read about how Linux handles idle time and C-states in &lt;a href=&#34;https://www.kernel.org/doc/html/latest/admin-guide/pm/cpuidle.html&#34;&gt;the Linux documentation on CPU Idle Time Management.&lt;/a&gt;&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Connecting to Firestore - Link-Sharing Site Part 3</title>
      <link>https://adamjhawley.com/post/2022-04-26-creating-a-link-sharing-site-part-3/</link>
      <pubDate>Tue, 26 Apr 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-04-26-creating-a-link-sharing-site-part-3/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-04-26-creating-a-link-sharing-site-part-3/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#handling-authentication&#34;&gt;Handling Authentication&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#web-component-redirects&#34;&gt;Web Component Redirects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#signing-in&#34;&gt;Signing In&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#firestore&#34;&gt;Firestore&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#adding-links&#34;&gt;Adding Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reading-links&#34;&gt;Reading Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;New to this series? Start
&lt;a href=&#34;https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/&#34;&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div id=&#34;introduction&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Thanks for taking the time to join me on my journey to create a new link-sharing
site. In the &lt;a href=&#34;https://adamjhawley.com/post/2022-03-14-creating-a-link-sharing-site-part-2/&#34;&gt;last post&lt;/a&gt;
I talked about how I initialised Firebase. Today I get to talk about how I
hooked the web app up to work with Firebase’s offerings. In particular I will
cover how I connected Firestore and gave users a way to submit and view links
stored on it.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;handling-authentication&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Handling Authentication&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&#34;https://adamjhawley.com/post/2022-03-14-creating-a-link-sharing-site-part-2/#creating-an-sign-up-page&#34;&gt;previous post&lt;/a&gt;,
I also described how I used the Firebase SDK function
&lt;a href=&#34;https://firebase.google.com/docs/auth/web/password-auth#create_a_password-based_account&#34;&gt;&lt;code&gt;createUserWithEmailAndPassword()&lt;/code&gt;&lt;/a&gt;
to connect a sign-up form to Firebase Authentication.&lt;/p&gt;
&lt;p&gt;Even after signing up, I presumed that I would first have to create the account
and then call a sign in function separately. However the Firebase SDK makes it
easier than that! If an account is successfully created then the user is
automatically signed in.&lt;/p&gt;
&lt;div id=&#34;web-component-redirects&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Web Component Redirects&lt;/h3&gt;
&lt;p&gt;So, a user has created an account and been signed in. At this point, most sites
I know redirect the user back to their previous page or another specific page.
To simplify things, I opted to redirect the user to the ‘browse’ page whenever
they have signed in. This page is the page where users can ‘browse’ all of the
recently added links, it also acts as the home page (see below).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/browse_page.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Initially, &lt;code&gt;createAccount()&lt;/code&gt; looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAccount(email, password) {
  const auth = getAuth();
  createUserWithEmailAndPassword(auth, email, password)
  .then((userCredential) =&amp;gt; {
      const user = userCredential.user;
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first, I called &lt;code&gt;createAccount()&lt;/code&gt; and then immediately redirected the user to
a new page. &lt;strong&gt;Without waiting for the response to
&lt;code&gt;createUserWithEmailAndPassword()&lt;/code&gt;.&lt;/strong&gt; I quickly realised this was an issue,
whether the account creation was successful or not was not important. If a user
clicked the ‘submit’ button in the sign-up form, they were getting redirected,
authenticated or not.&lt;/p&gt;
&lt;p&gt;However, if an account is not created due to an error such as an invalid email
or password being used, then the user interface should give the user an
opportunity to amend their form entries. To get around this, I wrapped my
&lt;code&gt;createAccount()&lt;/code&gt; logic in a &lt;code&gt;Promise&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAccount(email, password) {
  return new Promise ((resolve, reject) =&amp;gt; {
    const auth = getAuth()
    createUserWithEmailAndPassword(auth, email, password)
    .then((userCredential) =&amp;gt; {
        this.user = userCredential.user;
        resolve()
    })
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a relative-newcomer to JavaScript, I am still trying to get to grips with
everything related to &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;await&lt;/code&gt;, &lt;code&gt;Promise&lt;/code&gt; etc. So for fellow newcomers,
I recently published &lt;a href=&#34;https://adamjhawley.com/post/2022-04-12-basics-of-javascript-promises/&#34;&gt;a guide on getting started with JavaScript Promises&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;signing-in&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Signing In&lt;/h3&gt;
&lt;p&gt;Users could create accounts, hurrah! But they couldn’t yet sign in without
making a new account every time. Doesn’t sound too user friendly to me…&lt;/p&gt;
&lt;p&gt;Keeping it as simple as possible, I put together a sign in page which looked
exactly the same as the sign up page. The only difference being what went on
when the user hit ‘submit’. My &lt;code&gt;signIn()&lt;/code&gt; method is almost identical to
&lt;code&gt;createAccount()&lt;/code&gt;. The difference being that &lt;code&gt;signIn()&lt;/code&gt; uses
&lt;a href=&#34;https://firebase.google.com/docs/auth/web/password-auth#sign_in_a_user_with_an_email_address_and_password&#34;&gt;&lt;code&gt;signInWithEmailAndPassword()&lt;/code&gt;&lt;/a&gt; rather than the aforementioned &lt;code&gt;createUserWithEmailAndPassword()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/sign_in_page.png&#34; /&gt;
&lt;strong&gt;Working Sign-in Page&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now it’s time to celebrate! Working authentication hooked up to Firestore. Users
can now create accounts on the site and sign-in later.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;firestore&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Firestore&lt;/h2&gt;
&lt;div id=&#34;adding-links&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Adding Links&lt;/h3&gt;
&lt;p&gt;Onto the content of the site. We have already seen how users will view links on
the browse page in the &lt;a href=&#34;#web-component-redirects&#34;&gt;web component redirects
section&lt;/a&gt; and in &lt;a href=&#34;https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/#a-page-for-producing&#34;&gt;part 1 of the
series&lt;/a&gt;,
I showed how I created a page for submitting links but mentioned that the submit
button did nothing at all. Time for that to change!&lt;/p&gt;
&lt;p&gt;I started by creating an event handler &lt;code&gt;submitLink&lt;/code&gt; to handle when the submit
button in the form is pressed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get _form () {
  return this.renderRoot.querySelector(&amp;#39;#submit-form&amp;#39;)
}

async submitLink (e) {
  let userTitle = this._form.querySelector(&amp;#39;#title-input&amp;#39;).value
  let userLink = this._form.querySelector(&amp;#39;#link-input&amp;#39;).value
  const db = getFirestore(this.app);
  let col = collection(db, &amp;#39;links&amp;#39;)
  await addDoc(col, {
    link: userLink,
    title: userTitle
  })

  const event = new CustomEvent(&amp;#39;submitted-link&amp;#39;)
  this.dispatchEvent(event)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also amended the submit button in the template to use the new &lt;code&gt;submitLink&lt;/code&gt;
handler:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;sl-button @click=${this.submitLink}&amp;gt;Submit&amp;lt;/sl-button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the Firebase side of things, I start by using
&lt;a href=&#34;https://firebase.google.com/docs/firestore/quickstart#initialize&#34;&gt;getFirestore()&lt;/a&gt;.
I pass &lt;code&gt;this.app&lt;/code&gt; to &lt;code&gt;getFirestore()&lt;/code&gt; where &lt;code&gt;this.app&lt;/code&gt; is a property passed to
the web component equal to the output of
&lt;a href=&#34;https://firebase.google.com/docs/firestore/quickstart#initialize&#34;&gt;&lt;code&gt;initializeApp()&lt;/code&gt;&lt;/a&gt;.
The aim of this first line is to initialise a variable with access to the
database.&lt;/p&gt;
&lt;p&gt;Then I define &lt;code&gt;col&lt;/code&gt;, a variable with access to the specific collection within
the database:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let col = collection(db, &amp;#39;links&amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final step is to add the document containing the link to the collection:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await addDoc(col, {
  link: userLink,
  title: userTitle
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this operation is successful then we have added the link to the database!
Following this, I use the same strategy as described
&lt;a href=&#34;#web-component-redirects&#34;&gt;earlier&lt;/a&gt; to redirect the user to a new page by
dispatching a custom event.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;reading-links&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Reading Links&lt;/h3&gt;
&lt;p&gt;Luckily reading from Firestore is very similar to writing to it. Here are the
lines I use to get all of the available links from the links collection:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const db = getFirestore(this.app)
let col = collection(db, &amp;#39;links&amp;#39;)
const querySnapshot = await getDocs(col)
querySnapshot.forEach((doc) =&amp;gt; {
  this.linkBoxes.push(doc.data())
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first two lines are exactly the same as writing and follow exactly what I
described in &lt;a href=&#34;#adding-links&#34;&gt;the previous part&lt;/a&gt;. Things change a little in the
third line.&lt;/p&gt;
&lt;p&gt;A
&lt;a href=&#34;https://firebase.google.com/docs/reference/js/v8/firebase.firestore.QuerySnapshot&#34;&gt;&lt;code&gt;querySnapshot&lt;/code&gt;&lt;/a&gt;
contains the results of a query. By using &lt;code&gt;getDocs()&lt;/code&gt; on the whole collection
&lt;code&gt;col&lt;/code&gt;, I am asking to return all of the documents in the collection into the
variable &lt;code&gt;querySnapshot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the query is resolved, I loop through each document and add them to the
list of links shown on the browse page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: to access the contents of each document you have to iterate through each
and call its &lt;code&gt;.data()&lt;/code&gt; method.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s all there is to it! Link submission works and now the home page is
populated using links properly submitted by the user(s).&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this update I have discussed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#web-component-redirects&#34;&gt;How I used JavaScript promises to perform redirects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#signing-in&#34;&gt;How the sign-in page came to existence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#adding-links&#34;&gt;How users gained the ability to submit links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reading-links&#34;&gt;How the home page dynamically loads links from Firestore&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I sincerely hope you have enjoyed this update. If you would like to hear when I
publish more updates, sign up to the mailing list below or follow me on &lt;a href=&#34;https://twitter.com/_adamjhawley&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>Get Started with JavaScript Promises (in Under 2 Minutes)</title>
      <link>https://adamjhawley.com/post/2022-04-12-basics-of-javascript-promises/</link>
      <pubDate>Tue, 12 Apr 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-04-12-basics-of-javascript-promises/</guid>
      
      <description>&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;Welcome to an extremely brief introduction to JavaScript Promises. After getting
to grips with Promises myself I thought I would share the essentials that I
needed to put them into practice.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;basics-of-js-promises&#34;&gt;Basics of JS Promises&lt;/h2&gt;
&lt;p&gt;Promises can be defined with the following recipe:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function function1 () {
  return new Promise ((resolve, reject) =&amp;gt; {
    try {
      doSomeStuff()
      resolve()
    } catch (err) {
      reject(err) 
    }
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;resolve()&lt;/code&gt; should be called if the operation associated with the Promise
has been successful. &lt;code&gt;reject()&lt;/code&gt; should be called if the Promise could not be
&lt;strong&gt;resolved&lt;/strong&gt;, maybe there was some sort of problem when trying to perform the
associated operation.&lt;/p&gt;
&lt;p&gt;The caller function then has the option to asynchronously wait for the Promise
to resolve using &lt;code&gt;await&lt;/code&gt; or the &lt;code&gt;then()&lt;/code&gt; method of Promises. To use &lt;code&gt;await&lt;/code&gt;,
declare the entire function as asynchronous using the &lt;code&gt;async&lt;/code&gt; keyword. Here are
examples of both:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function callerFunc1() {
  // Use &#39;await&#39;
  await function1()
}
  
function callerFunc2() {
  // Use &#39;.then()&#39;
  function1().then(() =&amp;gt; {
    doSomethingAfterwards() 
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two extra things about &lt;code&gt;Promise.then()&lt;/code&gt;. Firstly, we can chain &lt;code&gt;.then()&lt;/code&gt; statements together to make something that operates like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function callerFunc3() {
  function1.then(() =&amp;gt; {
    console.log(&#39;First thing finished&#39;)
  }).then(() =&amp;gt; {
    console.log(&#39;Second thing finished&#39;)
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Secondly, &lt;code&gt;then()&lt;/code&gt; can actually take two arguments: one in case the Promise
&lt;strong&gt;resolves&lt;/strong&gt; and another to handle the case when the Promise &lt;strong&gt;rejects&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function callerFunc4() {
  function1.then(() =&amp;gt; {
    console.log(&#39;Everything went to plan!&#39;)
  }, () =&amp;gt; {
    console.log(&#39;The Promise rejected :(&#39;)
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want to see these examples in action, check out &lt;a href=&#34;https://stackblitz.com/edit/js-mkctvv?devToolsHeight=33&amp;amp;file=index.js&#34;&gt;this StackBlitz&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully you found this helpful, to get updates as soon as I release helpful
guides such as this follow me on &lt;a href=&#34;https://twitter.com/_adamjhawley&#34;&gt;Twitter&lt;/a&gt; or
sign up to my mailing list below!&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Initialising a Firebase App - Link-Sharing Site Part 2</title>
      <link>https://adamjhawley.com/post/2022-03-14-creating-a-link-sharing-site-part-2/</link>
      <pubDate>Mon, 14 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-03-14-creating-a-link-sharing-site-part-2/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-03-14-creating-a-link-sharing-site-part-2/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deciding-on-a-storage-solution&#34;&gt;Deciding on a Storage Solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#firebase&#34;&gt;Firebase&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#init-firebase&#34;&gt;Initialising a Firebase Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#problems-with-firebaseui&#34;&gt;Problems with FirebaseUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-an-sign-up-page&#34;&gt;Creating an Sign-Up Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;New to this series? Start
&lt;a href=&#34;https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/&#34;&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div id=&#34;introduction&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Welcome to the latest update in the “Creating a Link-Sharing Website” series
where I try to build a StackExchange and HackerNews crossover. Before this
update, I had a couple of working UI elements and (hopefully) a cool idea. See
my &lt;a href=&#34;https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/&#34;&gt;last post&lt;/a&gt; to see
exactly how I got started building out the first core UI elements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you want to jump straight to reading how I got started with Firebase, &lt;a href=&#34;#init-firebase&#34;&gt;click
here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I concluded the last post by discussing how my top priority was to consider
database solutions. This is because, at that point, a user could interact with the
UI and &lt;em&gt;‘submit’&lt;/em&gt; links to the website but with no real effect. The UI would
simply gobble up the form entries and do nothing with them. Content generation
that doesn’t involve generating content? Sounds pretty redundant to me.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;deciding-on-a-storage-solution&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Deciding on a Storage Solution&lt;/h1&gt;
&lt;p&gt;So I needed a way to store the links users would be uploading to the website.
Naturally, I started to consider a number of database solutions I have used in
the past.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.mongodb.com/&#34;&gt;MongoDB&lt;/a&gt;: a document-based NoSQL database that I
have extensive prior experience with.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://firebase.google.com/&#34;&gt;Firebase&lt;/a&gt;: actually a whole suite
of services provided by Google. It includes, but is not limited to, two
different database offerings, an authentication service and hosting.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.elastic.co/elasticsearch/&#34;&gt;ElasticSearch&lt;/a&gt;: in the past, I have
worked with ElasticSearch as a database for storing text data. Because of this,
I know that it has extremely powerful search and query capabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When evaluating the different choices I had to think about what I was going to
be storing. URLs and the title’s of the pages. Text. The basis of the site is
for people to share website links. If I want people to be able to share and view
them, I have to store them somewhere. Specifically, my plan is to store simple objects in the form:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  url: &amp;quot;https://adamjhawley.com/post/2022-02-07-using-git-rebase-to-perfect-commits/&amp;quot;,
  title: &amp;quot;Using &amp;#39;git rebase&amp;#39; to Perfect Commits&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even though MongoDB would definitely be up to the job if I had opted to select
it, I ultimately disregarded it. It was going to do exactly what it said on the
tin; no more, no less. It would serve as a document-based database with
developer-friendly APIs. So this would have definitely been my choice if another
wasn’t so tempting…&lt;/p&gt;
&lt;p&gt;Despite the fact that I had experience using ElasticSearch to quickly navigate
mountains of text data, I had an important realisation. I was not going to be
doing any complicated queries. So what’s the point? I had to stop myself from
dodging &lt;a href=&#34;https://en.wikipedia.org/wiki/Occam%27s_razor&#34;&gt;Occam’s razor&lt;/a&gt; and
consider something else.&lt;/p&gt;
&lt;p&gt;It is important to me to keep the website true to itself. I know from experience
that I, like many other developers, am easily distracted by the thought of
adding cool new features, insights and analytics to websites long before they
are necessary.&lt;/p&gt;
&lt;p&gt;Now onto Firebase. As I mentioned earlier, Firebase is rather a whole suite of
services provided by Google. Apart from a storage solution, Firebase offers
&lt;a href=&#34;https://firebase.google.com/products/hosting&#34;&gt;hosting&lt;/a&gt;,
&lt;a href=&#34;https://firebase.google.com/products/auth&#34;&gt;authentication&lt;/a&gt; and several other
services.&lt;/p&gt;
&lt;p&gt;Initially it might appear as if I am going against what I just said with regards
to keeping things as simple as possible. However, there is a key difference
between the extra features of Elasticsearch and the other services offered by
Firebase.&lt;/p&gt;
&lt;p&gt;Solutions for hosting and authentication are things I would need to even get the
base functionality of the site off the ground. For example, without a way to
host the site, there is no way for users to reach it. Of course, I could handle
this myself but that would involve taking on a considerably large amount of
work. Remember, at this point, &lt;a href=&#34;https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/&#34;&gt;I am focusing on an MVP&lt;/a&gt;. Furthermore, I am
considering making the website open source as a template for other developers to
use. By using Firebase it means that it would be much easier for someone else to
pick up the project. All they need is a Google account!&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;firebase&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Firebase&lt;/h1&gt;
&lt;div id=&#34;init-firebase&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Initialising a Firebase Project&lt;/h3&gt;
&lt;p&gt;So how did I actually get started? The first thing I did was turn to the
Firebase &lt;a href=&#34;https://firebase.google.com/docs/web/setup&#34;&gt;web documentation on getting
started&lt;/a&gt;.
From there I followed the following steps:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Created a Firebase project using the &lt;a href=&#34;https://console.firebase.google.com/u/0/&#34;&gt;Firebase
console&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Installed the &lt;a href=&#34;https://firebase.google.com/docs/cli/#install-cli-mac-linux&#34;&gt;Firebase CLI
tools&lt;/a&gt;:
&lt;code&gt;npm install -g firebase-tools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Logged in using Firebase CLI: &lt;code&gt;firebase login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Initialised the project as a Firebase app: &lt;code&gt;firebase init&lt;/code&gt; with the following
configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/firebase-init-dialogue.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;&lt;code&gt;firebase init&lt;/code&gt; dialogue.&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: during the &lt;code&gt;firebase init&lt;/code&gt; dialogue you might get an error similar to the
following. Don’t panic. For some reason, Google requires that users create the
Firestore instance in the UI before it can be accessed with CLI tools. Simply
follow the URL in the error and create a Firebase instance in your browser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre fig.cap=&#34;`firebase init` error&#34;&gt;&lt;code&gt;Error: It looks like you haven&amp;#39;t used Cloud Firestore in this project before. Go
to https://console.firebase.google.com/project/&amp;lt;PROJECT-ID&amp;gt;/firestore to
create your Cloud Firestore database.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, Firebase CLI automatically generates a handful of config files which
it will use for deploying to Firebase, configuring storage etc.&lt;/p&gt;
&lt;p&gt;In order to submit links to Firestore (the Firebase storage service I have opted
for), it requires a working authentication system. By default, Firestore does
not allow for unrestricted access to the database. Besides, I plan to limit
users to only be able to post links if they are signed in to an account. So
authentication is a necessary step. So I decided it was best to start with it
rather than working around it and then having to come back and rework in future.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;problems-with-firebaseui&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Problems with FirebaseUI&lt;/h2&gt;
&lt;p&gt;During the process of setting up the application to use Firebase authentication,
I found &lt;em&gt;helpful&lt;/em&gt;
&lt;a href=&#34;https://firebase.google.com/docs/auth/web/firebaseui&#34;&gt;documentation&lt;/a&gt; on how to
use a pre-built UI for authentication which apparently allows for:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Multiple authentication providers (email/password, Google, Github etc.)&lt;/li&gt;
&lt;li&gt;Account linking&lt;/li&gt;
&lt;li&gt;Customisation&lt;/li&gt;
&lt;li&gt;One-tap sign-up and automatic sign-in&lt;/li&gt;
&lt;li&gt;Localised UI&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;This all sounded great. I tried to integrate this into the application but ran
into an issue trying to import the package.&lt;/p&gt;
&lt;p&gt;In the project, I use ES module imports. That is, imports in the format:&lt;/p&gt;
&lt;pre class=&#34;js&#34;&gt;&lt;code&gt;import x from &amp;#39;npm-module/app&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;script type=&#34;text/javascript&#34;&gt;
import x from &#39;npm-module/app&#39;;
&lt;/script&gt;
&lt;p&gt;For some reason, this doesn’t seem to be supported by the FirebaseUI. &lt;a href=&#34;https://github.com/firebase/firebaseui-web/issues/674&#34;&gt;This
GitHub issue&lt;/a&gt; has been
open since 2020 with no clear progress seemingly made.&lt;/p&gt;
&lt;p&gt;After reading through the issue thread I decided to abandon using the FirebaseUI
and build my own authentication UI.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;creating-an-sign-up-page&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Creating an Sign-Up Page&lt;/h2&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/sign-up-page.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Link-Sharer sign-up page.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Using shoelace.style’s helpful &lt;a href=&#34;https://shoelace.style/components/input&#34;&gt;&lt;code&gt;&amp;lt;sl-input&amp;gt;&lt;/code&gt;
elements&lt;/a&gt; with built-in input
validation for emails, I put together a sign-up page with a component with the
following render functions:&lt;/p&gt;
&lt;pre class=&#34;js&#34;&gt;&lt;code&gt;
get _form () {
  return this.renderRoot.querySelector(&amp;#39;#signupform&amp;#39;)
}
  
handleSubmit (event) {
  let email = this._form.querySelector(&amp;#39;#email&amp;#39;).value
  let password = this._form.querySelector(&amp;#39;#password&amp;#39;).value
  this.createAccount(email, password)
  this.signIn(email, password)
}

render() {
  return html`
      &amp;lt;div id=&amp;quot;signupform&amp;quot;&amp;gt;
          &amp;lt;sl-input id=&amp;quot;email&amp;quot; label=&amp;quot;Email&amp;quot; type=&amp;quot;email&amp;quot; placeholder=&amp;quot;Enter email here&amp;quot; clearable&amp;gt;&amp;lt;/sl-input&amp;gt;
          &amp;lt;sl-input id=&amp;quot;password&amp;quot; label=&amp;quot;Password&amp;quot; type=&amp;quot;password&amp;quot; toggle-password placeholder=&amp;quot;Enter password here&amp;quot;&amp;gt;&amp;lt;/sl-input&amp;gt;
          &amp;lt;br&amp;gt;
          &amp;lt;sl-button @click=${this.handleSubmit}&amp;gt;Submit&amp;lt;/sl-button&amp;gt;
      &amp;lt;/div&amp;gt;
  `;
}&lt;/code&gt;&lt;/pre&gt;
&lt;script type=&#34;text/javascript&#34;&gt;

get _form () {
  return this.renderRoot.querySelector(&#39;#signupform&#39;)
}
  
handleSubmit (event) {
  let email = this._form.querySelector(&#39;#email&#39;).value
  let password = this._form.querySelector(&#39;#password&#39;).value
  this.createAccount(email, password)
  this.signIn(email, password)
}

render() {
  return html`
      &lt;div id=&#34;signupform&#34;&gt;
          &lt;sl-input id=&#34;email&#34; label=&#34;Email&#34; type=&#34;email&#34; placeholder=&#34;Enter email here&#34; clearable&gt;&lt;/sl-input&gt;
          &lt;sl-input id=&#34;password&#34; label=&#34;Password&#34; type=&#34;password&#34; toggle-password placeholder=&#34;Enter password here&#34;&gt;&lt;/sl-input&gt;
          &lt;br&gt;
          &lt;sl-button @click=${this.handleSubmit}&gt;Submit&lt;/sl-button&gt;
      &lt;/div&gt;
  `;
}
&lt;/script&gt;
&lt;p&gt;Where &lt;code&gt;createAccount()&lt;/code&gt; and &lt;code&gt;signIn()&lt;/code&gt; use the &lt;a href=&#34;https://firebase.google.com/docs/auth/web/password-auth&#34;&gt;Firebase authentication SDK&lt;/a&gt;. For
example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAccount(email, password) {
  const auth = getAuth();
  createUserWithEmailAndPassword(auth, email, password)
  .then((userCredential) =&amp;gt; {
      const user = userCredential.user;
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A couple of interesting things here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I linked &lt;code&gt;handleSubmit()&lt;/code&gt; to the click event of the &lt;code&gt;&amp;lt;sl-button&amp;gt;&lt;/code&gt; element
using &lt;code&gt;@click=${this.handleSubmit}&lt;/code&gt;. For more information, see the lit
documentation on &lt;a href=&#34;https://lit.dev/docs/components/events/#adding-event-listeners-in-the-element-template&#34;&gt;&lt;em&gt;adding event listeners in the element
template&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_form&lt;/code&gt; acts as a way to make the child &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element accessible throughout
the component and to parent components. This technique is also documented in
the lit documentation. See &lt;a href=&#34;https://lit.dev/docs/components/shadow-dom/#accessing-nodes-in-the-shadow-dom&#34;&gt;&lt;em&gt;accessing nodes in the shadow
DOM&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;At the end of this update I have a working way for users to sign up! I had hoped
to have a working storage solution by this point but I am happy with the
progress I have made. I think the time I have invested into setting up Firebase
will pay dividends in future when it comes to integrating with other services.&lt;/p&gt;
&lt;p&gt;Only time will tell! Make sure you sign up to my mailing list below to find out!&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>Creating a Link-Sharing Site Part 1</title>
      <link>https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/</link>
      <pubDate>Fri, 04 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-03-04-creating-a-link-sharing-site-part-1/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building-the-basics&#34;&gt;Building the Basics&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#a-page-for-consuming&#34;&gt;A Page for Consuming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#a-page-for-producing&#34;&gt;A Page for Producing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Welcome to the first update on my journey to creating a link-sharing site.
If you are interested in what I am doing and why I am doing it check out the
&lt;a href=&#34;https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/&#34;&gt;introduction to the series&lt;/a&gt;.
And if you want to get notified when I post new updates, follow me on
&lt;a href=&#34;https://twitter.com/_adamjhawley&#34;&gt;Twitter&lt;/a&gt; or sign up to &lt;a href=&#34;#mailing-list&#34;&gt;my mailing
list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have prioritised getting something functional.
This means that I haven’t exactly created anything &lt;em&gt;beautiful&lt;/em&gt; yet.
But I’m sure that will be very obvious.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;building-the-basics&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Building the Basics&lt;/h2&gt;
&lt;p&gt;I broke down my requirements based on the pages and functionality I needed to
create to get an MVP (&lt;a href=&#34;https://en.wikipedia.org/wiki/Minimum_viable_product&#34;&gt;minimum viable product&lt;/a&gt;) up and running.&lt;/p&gt;
&lt;div id=&#34;a-page-for-consuming&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;A Page for Consuming&lt;/h3&gt;
&lt;p&gt;Link-sharing websites are, simply put, a platform for facilitating content
consumption.
That is, the &lt;em&gt;‘content creation’&lt;/em&gt; side of this website is limited to a user
providing a link and a title.
At least for the time being…
Furthermore, I expect the majority of users to spend much more time
&lt;strong&gt;consuming&lt;/strong&gt; content rather than &lt;strong&gt;producing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Therefore, I need a way for users to find content to consume!
This page will probably act as the home page for the site.&lt;/p&gt;
&lt;p&gt;My current intention is for this page to simply contain a list of cards where
each one contains just the title of the link.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-1&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/list-page-screenshot.png&#34; alt=&#34;Screenshot of my &#39;browsing&#39; page&#34; width=&#34;621&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 1: Screenshot of my ‘browsing’ page
&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;a-page-for-producing&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;A Page for Producing&lt;/h3&gt;
&lt;p&gt;Then again, what’s the point in a page for consuming content if there is no
content to be consumed!
Sounds like I can’t get away with not building a page
for submitting links to the site.&lt;/p&gt;
&lt;p&gt;So, as I said, I went ahead and made it as minimal as possible.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-2&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/submit-page-screenshot.png&#34; alt=&#34;Screenshot of my &#39;submit&#39; page&#34; width=&#34;621&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 2: Screenshot of my ‘submit’ page
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now it’s worth noting that for the time being, that ‘Submit’ button sends the
link nowhere.
My plan is to hook this up to a database which will contain all of the links on
the site.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That’s all I have for this update.
My main priority in upcoming updates will be hooking up the site to use a
persistent database to store the links.
It has been great fun getting started with this project and I am very excited to
see where it can go!&lt;/p&gt;
&lt;p&gt;I know that I am new to the concept of ‘sharing your work’ but I know
consistency is key so stay tuned for another post coming soon!&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;mailing-list&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>Creating a Link-Sharing Site Part 0</title>
      <link>https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/</link>
      <pubDate>Wed, 16 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-02-16-creating-a-link-sharing-site-part-0/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#motivation---why-am-i-doing-this&#34;&gt;Motivation - Why am I doing this?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#showing-my-work&#34;&gt;Showing My Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#technology---how-am-i-going-to-build-this-thing&#34;&gt;Technology - How am I going to build this thing?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#keep-in-touch&#34;&gt;Keep in Touch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Welcome to a new series of blog posts.
In this series I will be sharing my progress on a new project.
What’s the new project?
I want to create a link-sharing site similar to
&lt;a href=&#34;https://news.ycombinator.com/&#34;&gt;HackerNews&lt;/a&gt; but with the flexibility of
&lt;a href=&#34;https://stackexchange.com/&#34;&gt;StackExchange&lt;/a&gt;.
Read on for more details.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;motivation---why-am-i-doing-this&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Motivation - Why am I doing this?&lt;/h3&gt;
&lt;p&gt;As an avid reader of &lt;a href=&#34;https://news.ycombinator.com/&#34;&gt;HackerNews&lt;/a&gt; one day I
started to wonder if this kind of site exists in other domains. I knew that
aggregators were popular in areas like finding new music but these tend to be
more complex.&lt;/p&gt;
&lt;p&gt;The thing I love about HackerNews is the organic growth of different links.
When a link is shared on the site it is not surrounded by some long description
or backstory. Just the title of the page. This means that the quality of the
link is evaluated by readers based on the content rather than how well the
poster is able to dress up the page with a misleading or exaggerating
description.&lt;/p&gt;
&lt;p&gt;As a developer, I also spend a lot of time on another site,
&lt;a href=&#34;https://stackoverflow.com/&#34;&gt;StackOverflow&lt;/a&gt; or more generally, &lt;a href=&#34;https://stackexchange.com/&#34;&gt;StackExchange&lt;/a&gt;. One interesting thing I find about
StackExchange is the way that it has taken a concept which works in separate
domains and implemented it across them separately. For example, as well as
StackOverflow for programming, there is also
&lt;a href=&#34;english.stackexchange.com&#34;&gt;english.stackexchange.com&lt;/a&gt; and
&lt;a href=&#34;mathematics.stackexchange.com&#34;&gt;mathematics.stackexchange.com&lt;/a&gt; for English and
maths respectively. See a full list here: &lt;a href=&#34;https://stackexchange.com/sites&#34;&gt;https://stackexchange.com/sites&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Considering these two sites I spend an awful lot of time on, I thought I would
try to create a network of link sharing sites across different domains.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;showing-my-work&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Showing My Work&lt;/h3&gt;
&lt;p&gt;Recently, I finished reading &lt;a href=&#34;https://www.goodreads.com/book/show/18290401-show-your-work&#34;&gt;‘Show Your Work!’ by Austin Kleon&lt;/a&gt; (and I
highly recommend it)! To complement this, I recently listened to &lt;a href=&#34;https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics&#34;&gt;a great Indie Hackers podcast with Josh Pigford&lt;/a&gt;.
Both of these inspired me to get into the habit of sharing my work.
My blog itself is still in its infancy and I am trying to build up a habit of
posting more regularly both as a good incentive to publicise work I produce and
to track my learning with time.&lt;/p&gt;
&lt;p&gt;Because of this I plan to blog my progress on this project and will be open to
any feedback. If you want to keep updated with my progress, I strongly recommend
signing up to my mailing list &lt;a href=&#34;#mailing-list&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;technology---how-am-i-going-to-build-this-thing&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Technology - How am I going to build this thing?&lt;/h3&gt;
&lt;p&gt;I have recently been picking up some experience using &lt;a href=&#34;https://lit.dev/&#34;&gt;lit&lt;/a&gt;
and have found that it provides a very quick and easy way to get going with web
components. This is about all the thinking I wanted to do at this point. Too
often I get bogged down planning and deciding on frameworks, languages etc. This
time I wouldn’t let that happen. For better or for worse…&lt;/p&gt;
&lt;p&gt;One thing I had heard of but not had the chance to use was the &lt;a href=&#34;https://github.com/lit/lit-element-starter-js&#34;&gt;Lit element
JavaScript project template&lt;/a&gt;.
So this is going to act as the baseline for the project.&lt;/p&gt;
&lt;p&gt;Here’s the first element I created which is incredibly basic. &lt;code&gt;LinkBox&lt;/code&gt; refers
to a box or card containing the link someone has shared.&lt;/p&gt;
&lt;pre class=&#34;js&#34;&gt;&lt;code&gt;import {LitElement, html} from &amp;#39;lit&amp;#39;;

/**
 * A small box containing a link and a title.
 */
export class LinkBox extends LitElement {

  static get properties() {
    return {
      /**
       * The title of the link.
       * @type {string}
       */
      name: {type: String},

      /**
       * The link itself.
       * @type {string}
       */
      link: {type: String},
    };
  }

  constructor() {
    super();
  }

  render() {
    return html`
      &amp;lt;a href=${this.link}&amp;gt;&amp;lt;sl-button&amp;gt;${this.name}&amp;lt;/sl-button&amp;gt;&amp;lt;/a&amp;gt;
    `;
  }
}

window.customElements.define(&amp;#39;ls-link-box&amp;#39;, LinkBox);&lt;/code&gt;&lt;/pre&gt;
&lt;script type=&#34;text/javascript&#34;&gt;
import {LitElement, html} from &#39;lit&#39;;

/**
 * A small box containing a link and a title.
 */
export class LinkBox extends LitElement {

  static get properties() {
    return {
      /**
       * The title of the link.
       * @type {string}
       */
      name: {type: String},

      /**
       * The link itself.
       * @type {string}
       */
      link: {type: String},
    };
  }

  constructor() {
    super();
  }

  render() {
    return html`
      &lt;a href=${this.link}&gt;&lt;sl-button&gt;${this.name}&lt;/sl-button&gt;&lt;/a&gt;
    `;
  }
}

window.customElements.define(&#39;ls-link-box&#39;, LinkBox);
&lt;/script&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;keep-in-touch&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Keep in Touch&lt;/h3&gt;
&lt;p&gt;For now, this is where I am. I aim to post roughly once a week with updates on
my progress. I hope you enjoyed reading and wish me luck!
As mentioned earlier, if you want to get updates straight to your inbox,
consider joining my mailing list below.&lt;/p&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a id=&#34;mailing-list&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>Using &#39;git rebase&#39; to Perfect Commits</title>
      <link>https://adamjhawley.com/post/2022-02-07-using-git-rebase-to-perfect-commits/</link>
      <pubDate>Mon, 07 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-02-07-using-git-rebase-to-perfect-commits/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-02-07-using-git-rebase-to-perfect-commits/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;


&lt;p&gt;I have long tried to get into the good habit of committing as I develop.
However, I often fell into the same scenario. On commit №4, I would realise that
I should have worked something differently in commit №2.&lt;/p&gt;
&lt;p&gt;Naively, my old approach was a combination of adding extra re-work commits and
different forms of &lt;code&gt;git reset&lt;/code&gt;. &lt;code&gt;git rebase&lt;/code&gt; to the rescue!&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;git rebase -i&lt;/code&gt; command was everything I believed had to be part of git but
didn’t know of. The &lt;code&gt;-i&lt;/code&gt; flag is the ‘interactive’ mode of &lt;code&gt;git rebase&lt;/code&gt;. Which
allows you to choose which commits you want to rebase.&lt;/p&gt;
&lt;p&gt;Let’s have a look at an example to illustrate:&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-1&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram1.png&#34; alt=&#34;`git log` output before correcting my mistake&#34; width=&#34;461&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 1: &lt;code&gt;git log&lt;/code&gt; output before correcting my mistake
&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;p&gt;At this point I made a mistake a couple of commits ago and have even made
further changes to some of the bad code I have written as part of future
commits.&lt;/p&gt;
&lt;p&gt;To go back in time, I use &lt;code&gt;git rebase -i &amp;lt;COMMIT_ID&amp;gt;&lt;/code&gt;. Where &lt;code&gt;&amp;lt;COMMIT_ID&amp;gt;&lt;/code&gt; is
the commit id of a commit BEFORE my mistake.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-2&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram2.png&#34; alt=&#34;`git rebase -i`&#34; width=&#34;581&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 2: &lt;code&gt;git rebase -i&lt;/code&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;p&gt;As shown in the helpful comments, there are many commands I can use for each
commit and each one is explained. The commands I use most-frequently are ‘edit’
and ‘reword’ (‘reword’ is for the times when you have a typo in your commit
message).&lt;/p&gt;
&lt;p&gt;Here we can change &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;e&lt;/code&gt; or &lt;code&gt;edit&lt;/code&gt; next to our bad commit before saving
and closing the file.&lt;/p&gt;
&lt;p&gt;Then I can go in and change my mistake. Once the changes are made, I can &lt;code&gt;git commit --amend&lt;/code&gt; to fix the commit itself.&lt;/p&gt;
&lt;p&gt;Once my initial mistakes have been corrected and git knows about the fixes I can
use &lt;code&gt;git rebase --continue&lt;/code&gt;. git will now try to apply my old commits (№3 &amp;amp; №4)
on top of my fixes.&lt;/p&gt;
&lt;p&gt;If there are any conflicts git will let you know. These happen in this case if
your fix for the broken code replaced some of the code that you changed in
later, good commits.&lt;/p&gt;
&lt;p&gt;You should solve the conflicts so that the code is as you would want it at that
commit. Importantly, you should stop before using &lt;code&gt;git commit --amend here&lt;/code&gt;. git
stopped to let you shape the commit in the way you want it and did not apply it
yet. This means that to save this rework in the same commit, you should just go
straight to &lt;code&gt;git rebase --continue&lt;/code&gt; where git will ask you to confirm/edit the
commit message.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-3&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram3.png&#34; alt=&#34;`git log` output as if nothing was ever any different…&#34; width=&#34;459&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 3: &lt;code&gt;git log&lt;/code&gt; output as if nothing was ever any different…
&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;p&gt;And there we have it! A clean git history with useful commits. Learning &lt;code&gt;git rebase&lt;/code&gt; has truly given me a greater confidence using git and helped increase
both my productivity and the quality of my work. I hope this you have managed to
learn something too and thanks for reading this far!&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Mastering ‘git’ with ‘git rebase’</title>
      <link>https://adamjhawley.com/post/2022-02-04-mastering-git-with-git-rebase/</link>
      <pubDate>Fri, 04 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2022-02-04-mastering-git-with-git-rebase/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2022-02-04-mastering-git-with-git-rebase/index.en_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#what-does-git-rebase-actually-do&#34;&gt;What does ‘git rebase’ actually do?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
Recently, I started a new job. I sat down, checked out some repos, and cracked
on with some work. When I was ready to commit my first changes, I typed &lt;code&gt;git log&lt;/code&gt; to see how my new colleagues like to format their commits… No merge
commits. A handful of devs all working on one branch simultaneously? What kind
of elegant version control choreography had to be involved? I knew something was
up…
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-1&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram1.png&#34; alt=&#34;What I was used to (a typical git-tree using `git merge`)&#34; width=&#34;681&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 1: What I was used to (a typical git-tree using &lt;code&gt;git merge&lt;/code&gt;)
&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-2&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram%202.png&#34; alt=&#34;What I saw (the same git-tree using `git rebase`)&#34; width=&#34;451&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 2: What I saw (the same git-tree using &lt;code&gt;git rebase&lt;/code&gt;)
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The answer? One command: &lt;code&gt;git rebase&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;what-does-git-rebase-actually-do&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;What does ‘git rebase’ actually do?&lt;/h1&gt;
&lt;p&gt;If we imagine the scenario below:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Starting on &lt;code&gt;grey-branch&lt;/code&gt; and running &lt;code&gt;git checkout -b blue-branch&lt;/code&gt; creates the
new branch &lt;code&gt;blue-branch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Commit two sets of changes with git commit&lt;/li&gt;
&lt;li&gt;Then, a teammate pushes a couple of commits to &lt;code&gt;grey-branch&lt;/code&gt; while your changes are still in review or you haven’t had time to merge.&lt;/li&gt;
&lt;li&gt;We switch back to &lt;code&gt;grey-branch&lt;/code&gt; and pull the changes our teammate added.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:prerebase&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram3.png&#34; alt=&#34;On the blue branch before ‘git rebase’&#34; width=&#34;452&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 3: On the blue branch before ‘git rebase’
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;At this point, I was used to using git merge where I would solve any conflicts
and create a merge commit, making the tree look like this:&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-3&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram4.png&#34; alt=&#34;Merging the two sets of changes with a merge&#34; width=&#34;1222&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 4: Merging the two sets of changes with a merge
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;However, instead of using &lt;code&gt;git merge&lt;/code&gt; , this is where &lt;code&gt;git rebase&lt;/code&gt; comes in. If I am
on &lt;code&gt;blue-branch&lt;/code&gt; in figure &lt;a href=&#34;#fig:prerebase&#34;&gt;3&lt;/a&gt; and I use &lt;code&gt;git rebase grey-branch&lt;/code&gt;, magic happens:&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-4&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram5.png&#34; alt=&#34;Merging the two sets of changes with `git rebase grey-branch`&#34; width=&#34;452&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 5: Merging the two sets of changes with &lt;code&gt;git rebase grey-branch&lt;/code&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Isn’t that so amazing? My commits have now been ‘rebased’ on top of the commits
in &lt;code&gt;grey-branch&lt;/code&gt; .&lt;/p&gt;
But the magic doesn’t end there. Once I use &lt;code&gt;git push blue-branch:grey-branch&lt;/code&gt; I
get this beauty:
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-5&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;images/diagram6.png&#34; alt=&#34;git elegance&#34; width=&#34;700&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 6: git elegance
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So satisfying… All the changes with their relevant commit info but discarding branch history and those (now) pointless merge commits!&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>GraDiAn - the Grammatical Distribution Analyser</title>
      <link>https://adamjhawley.com/post/2021-06-28-gradian/</link>
      <pubDate>Mon, 28 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2021-06-28-gradian/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2021-06-28-gradian/index_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#data-types&#34;&gt;Data Types&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#senttree&#34;&gt;SentTree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#syntactic-dependency-counter-sdc&#34;&gt;Syntactic Dependency Counter (SDC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#example-usage&#34;&gt;Example Usage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;The Grammatical Distribution Analyser (GraDiAn) is a Python library for analysing grammatical distributions; particularly with the aim of analysing NLP datasets.
The library was originally created as part of my Bachelor’s degree at the University of York.
Drift in grammatical distribution is often disregarded.
The intention of the project was to analyse state of the art NLP datasets for undocumented grammatical distribution drift.
Following the detection of such drift, the next stage would be to investigate the impact on machine learning models which such drift can cause.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;See the original report &lt;a href=&#34;https://adamjhawley.com/post/2021-06-28-gradian_files/report.pdf&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the purposes of the report and GraDiAn, grammatical distribution is defined as a measure of frequencies of various grammatical properties over of a text or series of texts.
One potential use for grammatical distribution could be outlining a particular author’s writing style.
Drift in grammatical distribution represents the idea that two datasets possess a statistically different grammatical distribution to each other.
One example of this effect is that machine learning datasets and benchmarks often contain multiple splits, importantly a ‘train’ split which the model learns from and a ‘test’ split which the model is evaluated against.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;data-types&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Data Types&lt;/h1&gt;
&lt;div id=&#34;senttree&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;SentTree&lt;/h2&gt;
&lt;p&gt;The first of the two abstract data types which GraDiAn provides is the SentTree structure.
The &lt;code&gt;SentTree&lt;/code&gt; class allows a user to categorise sentences based on parse-trees and the appearances of different linguistic properties of tokens on that tree.
For example, where a standard parse-tree may just display the tokens with the syntactic dependencies shown between elements; the &lt;code&gt;SentTree&lt;/code&gt; means that the tree could be expanded to include other attributes such as part-of-speech (POS) tags and sentiment.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;syntactic-dependency-counter-sdc&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Syntactic Dependency Counter (SDC)&lt;/h2&gt;
&lt;p&gt;The Syntactic Dependency Counter is a much simpler structure in comparison to the &lt;code&gt;SentTree&lt;/code&gt;.
The inspiration for the SDC class was a severe contrast to popular word-embedding techniques.
Where traditional word-embedding techniques discard explicit grammatical properties of the text, the SDC reduces text down to just its syntactic dependencies.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;example-usage&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Example Usage&lt;/h1&gt;
&lt;p&gt;In the report mentioned above, both SentTrees and SDCs were used to represent attributes of different data points in state of the art NLP datasets.
Each attribute was then evaluated for distribution drift between train and test splits.
Further work could include investigating the effect this drift can have on the performance of machine learning models.&lt;/p&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>TicTacGo - An Intro to Golang</title>
      <link>https://adamjhawley.com/post/2021-06-26-tictacgo/</link>
      <pubDate>Sat, 26 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2021-06-26-tictacgo/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/rmarkdown-libs/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#board&#34;&gt;Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-api&#34;&gt;The API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;I am a true beginner to &lt;a href=&#34;https://golang.org/&#34;&gt;the Go Programming Language&lt;/a&gt; and to solidify some of the basics I have acquired I set out on creating a naughts and crosses (tic-tac-toe) server as an introductory project.
You can find the project on my Github &lt;a href=&#34;https://github.com/adamjhawley/TicTacGo&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;board&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Board&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;Board&lt;/code&gt; is the struct I created to contain the current board state, the grid but more accurately the state contains the 9 cells in the grid and their contents.
At a given point, I cell on the grid can either contain nothing, “O” or “X”, where the latter two represent a naught and a cross respectively.
The struct contains only one attribute: Squares, of type &lt;code&gt;[9]string&lt;/code&gt;.
However, the &lt;code&gt;Board&lt;/code&gt; struct has several related methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DrawBoard() string&lt;/code&gt; :: returns a string which contains the HTML representation of the board.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Reset()&lt;/code&gt; :: resets the board to an empty state.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckLegal(i int) bool&lt;/code&gt; :: checks if a given move is legal in the current state (i.e. if the move correlates to an actual cell in the grid and that cell is empty).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckWin(x string) bool&lt;/code&gt; :: where x should be “O” or “X”, checks to see if the given player is in a winning state.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;the-api&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;The API&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;net/http&lt;/code&gt; package (see docs &lt;a href=&#34;https://golang.org/pkg/net/http/&#34;&gt;here&lt;/a&gt;) provides a very convenient way of creating an API.
Creating the endpoints is as simple as writing a handler function for the endpoint and then assigning that function to an endpoint.
Then serve the API using the &lt;code&gt;http.ListenAndServe&lt;/code&gt; function.
See below for a &lt;em&gt;bare-bones&lt;/em&gt; but complete example of a &lt;code&gt;net/http&lt;/code&gt; API.&lt;/p&gt;
&lt;pre echo=&#34;False,&#34; fig.cap=&#34;Complete net/http API example&#34;&gt;&lt;code&gt;// Example net/http API
package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;net/http&amp;quot;
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, &amp;quot;Here is a response!&amp;quot;)
}

func main(){
    http.HandleFunc(&amp;quot;/&amp;quot;, handler)
    log.Fatal(http.ListenAndServe(&amp;quot;localhost:8000&amp;quot;, nil))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In TicTacGo, I use the API to register moves made by players.
Specifically I have use a handler on the root endpoint &lt;code&gt;/&lt;/code&gt; called &lt;code&gt;makeMove&lt;/code&gt;.
&lt;code&gt;makeMove&lt;/code&gt; retrieves the player’s move from the path using &lt;code&gt;r.URL.Path&lt;/code&gt; where &lt;code&gt;r&lt;/code&gt; is passed to the handler function as an &lt;code&gt;*http.Request&lt;/code&gt;.
This is an impractical way to accept URL arguments and is far from standard but it is also not a concern for the tiny scope of this project.
&lt;code&gt;makeMove&lt;/code&gt; follows the following steps:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Accesses player’s move from path.&lt;/li&gt;
&lt;li&gt;Checks the move is legal (if it isn’t no move is made and the input is ignored).&lt;/li&gt;
&lt;li&gt;Makes the move by updating the &lt;code&gt;Squares&lt;/code&gt; attribute of the &lt;code&gt;Board&lt;/code&gt; struct with the appropriate character (“O” or “X”).&lt;/li&gt;
&lt;li&gt;Checks for a win condition; if there a player has won than it sends a message to say so before resetting the &lt;code&gt;Board&lt;/code&gt; with &lt;code&gt;Reset()&lt;/code&gt;; else it waits for the next move.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By using the URL as a way for the player to make moves it allows me to embed buttons within the HTML representation of the board.
This means that when the player clicks on the top-right cell on the board, the server will register their move with that cell.&lt;/p&gt;
&lt;!-- ![TicTacGo Board HTML Screenshot](/post/2021-06-26-tictacgo_files/tictacgo_screenshot.png) --&gt;
&lt;center&gt;
&lt;figure&gt;
&lt;img src=&#34;https://adamjhawley.com/post/2021-06-26-tictacgo_files/tictacgo_screenshot.png&#34; alt=&#34;TicTacGo Board HTML Screenshot&#34; width=&#34;200&#34;/&gt;
&lt;figcaption&gt;
TicTacGo Board HTML Screenshot
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>About</title>
      <link>https://adamjhawley.com/about/</link>
      <pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/about/</guid>
      
      <description>&lt;h2 id=&#34;about-me&#34;&gt;About Me&lt;/h2&gt;
&lt;p&gt;I am a first-class Computer Science graduate from the University of York working as a Software Engineer in the Linux Driver Department at Intel.
The aim of this blog is a place where I can share the new things I learn/develop so that it might be that bit smoother for others after me!&lt;/p&gt;
&lt;h2 id=&#34;contact-me&#34;&gt;Contact Me&lt;/h2&gt;
&lt;p&gt;Feel free to connect with me on any of the below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/_adamjhawley&#34;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.linkedin.com/in/adam-hawley/&#34;&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/adamjhawley&#34;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;work-experience&#34;&gt;Work Experience&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Company&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th style=&#34;text-align:right&#34;&gt;Duration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;Intel Corporation&lt;/td&gt;
&lt;td&gt;Software Engineer&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;October 2021 – Present&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;Versed AI&lt;/td&gt;
&lt;td&gt;Software Engineering Intern&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;November 2020 – September 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;Amadeus IT Services UK&lt;/td&gt;
&lt;td&gt;Software Developer Intern&lt;/td&gt;
&lt;td style=&#34;text-align:right&#34;&gt;July 2019 – July 2020&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;donate&#34;&gt;Donate&lt;/h2&gt;
&lt;p&gt;I have specifically chosen to host this blog in this way to avoid platforms which hide information behind paywalls.
If you would like to support the blog with a donation then please consider &lt;a href=&#34;https://www.buymeacoffee.com/adamhawley&#34;&gt;buying me a coffee&lt;/a&gt; or by donating crypto.&lt;/p&gt;
&lt;h4 id=&#34;monero&#34;&gt;Monero&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;87Z6Nw2Xa5bPM5ezuNssC8iEXeuCf5YPL711apDsGpdh51p8PWp3kAqRmRFW5GvdpHGf6B1vpqmSRPwGLWyhWdvS3ggvo4X&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://adamjhawley.com/blogdonatemonero.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Creating a Perceptron in PyTorch Lightning</title>
      <link>https://adamjhawley.com/post/2021-02-13-pytorch-lightning-perceptron/</link>
      <pubDate>Sat, 13 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/post/2021-02-13-pytorch-lightning-perceptron/</guid>
      
      <description>
&lt;script src=&#34;https://adamjhawley.com/post/2021-02-13-pytorch-lightning-perceptron/index_files/header-attrs/header-attrs.js&#34;&gt;&lt;/script&gt;

&lt;div id=&#34;TOC&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pytorch-lightning&#34;&gt;PyTorch Lightning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#code&#34;&gt;Code&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#creating-the-dataset&#34;&gt;Creating the Dataset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pytorchlightning-model&#34;&gt;PyTorchLightning Model&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#init-function&#34;&gt;Init Function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#feed-forward-function&#34;&gt;Feed Forward Function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#training-step&#34;&gt;Training Step&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#optimiser-configuration&#34;&gt;Optimiser Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#trainer&#34;&gt;Trainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#manual-evaluation&#34;&gt;Manual Evaluation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#complete-file&#34;&gt;Complete File&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&#34;introduction&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;In the grand-scheme of things, I am relatively new to ML and particularly neural networks.
Like all good nn students that have come before me, I started by learning about a single perceptron.
The perceptron is the most basic of neural network components.
A perceptron accepts an input of size &lt;span class=&#34;math inline&#34;&gt;\(n\)&lt;/span&gt; and has &lt;span class=&#34;math inline&#34;&gt;\(n + 1\)&lt;/span&gt; weights, where the extra weight is to handle a bias (think of the bias as a permanent input of value &lt;span class=&#34;math inline&#34;&gt;\(1*weight_{bias}\)&lt;/span&gt;, or if you prefer to think visually, the bias represents &lt;span class=&#34;math inline&#34;&gt;\(c\)&lt;/span&gt; in the &lt;span class=&#34;math inline&#34;&gt;\(y=mx + c\)&lt;/span&gt; rule).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;pytorch-lightning&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;PyTorch Lightning&lt;/h1&gt;
&lt;p&gt;PyTorch Lightning is a lightweight wrapper around PyTorch which aims to make PyTorch code easier to read, more concise and quicker to write.
If you are already with familiar with PyTorch but not PyTorch Lightning then you will be pleasantly surprised by its simplicity and if you are not familiar with PyTorch then you should find PyTorch Lightning code easier to pick up and understand for the first time.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;code&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Code&lt;/h1&gt;
&lt;p&gt;My aim was to create as simple an example as possible.
For this reason, I settled on creating a perceptron with one input-weight pair.
Its purpose: to double the input.&lt;/p&gt;
&lt;p&gt;To start, here are some of the imports I will be using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import torch
from torch import nn
from torch.utils.data import DataLoader, TensorDataset
import pytorch_lightning as pl
from pytorch_lightning import loggers as pl_loggers&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;creating-the-dataset&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Creating the Dataset&lt;/h2&gt;
&lt;p&gt;The perceptron needs to learn from data, hence the need to create a dataset.
On the first line, I define &lt;code&gt;train_size&lt;/code&gt;.
This variable describes the amount of data we want to train out model on.
Since we are building an extremely simple model, this number can be relatively small.
The dataset for this purpose is simple, we want the model to double inputs, so we need to give it numbers as inputs and then we tell it to compare its answer to double that input.
In the second line, I use python list comprehension and PyTorch’s randn function to generate a list of pairs where the first component is the input and the second is the expected answer (&lt;span class=&#34;math inline&#34;&gt;\(2 \times input\)&lt;/span&gt; in our case).
The first line is a way of simplifying later stages, we create a TensorDataset using the data we have just created.
This will allow us to pass the data easily to a trainer via a DataLoader.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;train_size = 20     # Size of training set
train_X = [[i, 2*i] for i in torch.randn(train_size, dtype=torch.double)]
dataset = TensorDataset(torch.tensor(train_X))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;pytorchlightning-model&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;PyTorchLightning Model&lt;/h2&gt;
&lt;p&gt;The class, &lt;code&gt;Times2Model&lt;/code&gt;, outlined in the code snippet below defines our PyTorch model.
PyTorchLightning allows us to create a PyTorch model by implementing the methods listed in shown in the snippet.&lt;/p&gt;
&lt;pre id=&#34;pt_model&#34;&gt;&lt;code&gt;torch.set_default_dtype(torch.double)

class Times2Model(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(1,1)
        self.criterion = nn.MSELoss()

    def forward(self, x):
        return self.fc1(x)

    def training_step(self, batch, batch_idx):
        x, y = batch
        y_hat = self(x)
        loss = self.criterion(y_hat, y)
        return loss

    def configure_optimizers(self):
        return torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;init-function&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Init Function&lt;/h3&gt;
&lt;p&gt;In the initialisation function we declare our model architecture using PyTorch to provide the Fully Connected or Linear layer along with the criterion function which we will use as our loss function.
Since we are creating a lone perceptron, our fully connected layer consists of just one node.
Our perceptron is learning to double a single given input, the layer needs just that; one input along with a single output (hence the &lt;code&gt;(1,1)&lt;/code&gt; pair passed to the Linear layer).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;feed-forward-function&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Feed Forward Function&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;forward(self, x)&lt;/code&gt;, we need to define what happens when the model receives an input.
Since we have such a simple model, we just pass the input, &lt;code&gt;x&lt;/code&gt;, through our fully connected perceptron and return the output.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note, this definition defines the behaviour of passing input to the model directly such as in &lt;code&gt;model(x)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div id=&#34;training-step&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Training Step&lt;/h3&gt;
&lt;p&gt;In the training step, the goal is to make a prediction with our model, calculate the error between its prediction and the expected value and then return the error so that the model can adjust its weight accordingly.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;optimiser-configuration&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Optimiser Configuration&lt;/h3&gt;
&lt;p&gt;In this function we define which optimiser for the model to use.
This optimiser then controls weight adjustment according to the parameters provided.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;trainer&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Trainer&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;trainer = pl.Trainer(max_epochs=5)
model = Times2Model()
train_loader = DataLoader(train_X)
trainer.fit(model, train_loader)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;manual-evaluation&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Manual Evaluation&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;for i in torch.randn(5, dtype=torch.double):
    print(f&amp;quot;Expected: {2*i}&amp;quot;)
    print(f&amp;quot;Actual: {model(torch.tensor([i]))[0]}&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above snippet generates 5 random samples to test our trained model on.
Then it prints the expected value (which we find by simply multiplying by 2) followed by the value outputted by the model.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for weight in model.parameters():
    print(weight)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally in this snippet, I print out the single weight (which should be extremely close to two if we have done things correctly!) and the bias (which should be 0).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;complete-file&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Complete File&lt;/h2&gt;
&lt;p&gt;View the complete python script (hosted on github) below:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/adamjhawley/3e1e592e244edb464fd5b2305b993a42.js&#34;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
      
    </item>
    
    <item>
      <title>POS Tags Simplified</title>
      <link>https://adamjhawley.com/post/2020-10-17-pos-tags-simplified/</link>
      <pubDate>Sat, 17 Oct 2020 11:32:14 +0300</pubDate>
      
      <guid>https://adamjhawley.com/post/2020-10-17-pos-tags-simplified/</guid>
      
      <description>&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#Introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#Tags&#34;&gt;Tags&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#Example&#34;&gt;Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#Methods&#34;&gt;Methods&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;Introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Part-of-Speech tagging is a very useful foundation of NLP and deeper NLP concepts.  The action involves analysing text and returning the tokens of the text with the appropriate Part-of-Speech (POS) tags.&lt;/p&gt;
&lt;h1 id=&#34;Tags&#34;&gt;POS Tags&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;POS Tag&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ADJ&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/ADJ.html&#34;&gt;adjective&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;super&lt;/strong&gt; cat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADP&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/ADP.html&#34;&gt;apposition&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;my &lt;strong&gt;friend Liam&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADV&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/ADV.html&#34;&gt;adverb&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The boy ran &lt;strong&gt;quickly&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AUX&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/AUX_.html&#34;&gt;auxiliary&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;He &lt;strong&gt;will&lt;/strong&gt; make&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CCONJ&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/CCONJ.html&#34;&gt;coordinating conjunction&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;this &lt;strong&gt;and&lt;/strong&gt; that&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DET&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/DET.html&#34;&gt;determiner&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;the&lt;/strong&gt; squirrel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INTJ&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/INTJ.html&#34;&gt;interjection&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Oi&lt;/strong&gt;!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOUN&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/NOUN.html&#34;&gt;noun&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;the &lt;strong&gt;dog&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NUM&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/NUM.html&#34;&gt;numeral&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;one&lt;/strong&gt; fork&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PART&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/PART.html&#34;&gt;particle&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;not&lt;/strong&gt; Sam &lt;strong&gt;&amp;rsquo;s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PRON&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/PRON.html&#34;&gt;pronoun&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;he&lt;/strong&gt; shouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PROPN&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/PROPN.html&#34;&gt;proper noun&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Helsinki&lt;/strong&gt; is beautiful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUNCT&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/PUNCT.html&#34;&gt;punctuation&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Hello &lt;strong&gt;,&lt;/strong&gt; there &lt;strong&gt;!&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCONJ&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/SCONJ.html&#34;&gt;subordinating conjunction&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;I do this &lt;strong&gt;while&lt;/strong&gt; they do that&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYM&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/SYM.html&#34;&gt;symbol&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;5 &lt;strong&gt;+&lt;/strong&gt; 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VERB&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/VERB.html&#34;&gt;verb&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;They &lt;strong&gt;think&lt;/strong&gt; that&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://universaldependencies.org/u/pos/X.html&#34;&gt;other&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;this &lt;strong&gt;asd;lfkjasd;flkj&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Source: &lt;a href=&#34;https://universaldependencies.org/u/pos/&#34;&gt;Universal POS tags&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Above is a list of the standardised POS tags. You will probably recognise many of them from English class.&lt;/p&gt;
&lt;h1 id=&#34;Example&#34;&gt;Example&lt;/h1&gt;
&lt;p&gt;Courtesy of Spacy’s visualiser (as always!), below I have included an example where the phrase “This is my house while I live here” has been analysed and POS tags have been assigned. You can see that the tags line up with what would be expected from the list above.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://adamjhawley.com/post/2020-10-17-pos-tags-simplified_files/POS-example.png&#34; alt=&#34;POS Tag Example&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;Methods&#34;&gt;How Are POS Tags Assigned?&lt;/h1&gt;
&lt;p&gt;There are many different ways that POS Tags are assigned. These methods include dynamic programming algorithms (such as the popular &lt;a href=&#34;https://en.wikipedia.org/wiki/Viterbi_algorithm&#34;&gt;Viterbi algorithm&lt;/a&gt;). It is common to see hidden Markov models implemented in POS-tagging algorithms. As with many modern NLP elements, machine learning is now very popular for POS-tagging. In this case, computers analyse corpora of text which has been appropriately tagged already and try to learn how to tag tokens itself.&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Named Entity Recognition (NER) Simplified</title>
      <link>https://adamjhawley.com/post/2020-09-12-named-entity-recognition-simplified/</link>
      <pubDate>Sat, 12 Sep 2020 20:53:28 +0300</pubDate>
      
      <guid>https://adamjhawley.com/post/2020-09-12-named-entity-recognition-simplified/</guid>
      
      <description>&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#definition&#34;&gt;Defining Named Entity Recognition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#NERProblems&#34;&gt;What makes NER Difficult&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#NERApproaches&#34;&gt;Current Approaches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#NERExperimenting&#34;&gt;Experimenting With NER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;This blog post is post number two in a series aimed at making Natural Language Processing topics more accessible by abstracting these topics away from mathematics and implementation details.&lt;/p&gt;
&lt;h1 id=&#34;definition&#34;&gt;Defining Named Entity Recognition&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Named Entity Recognition (NER) is the detection and labelling of named entities (organisations, people, locations etc.)  within a text.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is an example of what an NER analysis returns on a given sentence (using &lt;a href=&#34;https://spacy.io/usage/linguistic-features#named-entities-101&#34;&gt;spaCy&amp;rsquo;s NER and visualiser&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://dev-to-uploads.s3.amazonaws.com/i/ng6axdwrvefjixrkxuhx.png&#34; alt=&#34;spacy-ner-example&#34;&gt;&lt;/p&gt;
&lt;p&gt;Tags (labels such as &lt;em&gt;organisation&lt;/em&gt;) can vary between different systems and implementations but they will usually include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ORG&lt;/strong&gt;anisation&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;GPE&lt;/strong&gt;) Geo-Political Entities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PERSON&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Other categories you may encounter include &lt;em&gt;location&lt;/em&gt;, &lt;em&gt;money&lt;/em&gt; and &lt;em&gt;time&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id=&#34;NERProblems&#34;&gt;What Makes NER Difficult?&lt;/h1&gt;
&lt;p&gt;At first glance, the task can seem very easy. However, after considering a few examples it can equally quickly become clear how the task could be troublesome for a machine.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“First Lady Makes an Appearance at John Smith’s”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Are we discussing the first lady to ever exist or are we talking about the president’s wife here? Is John Smith&amp;rsquo;s a pub, a person&amp;rsquo;s house or something completely different? And, more importantly, how can a computer know?&lt;/p&gt;
&lt;h1 id=&#34;NERApproaches&#34;&gt;Approaches to NER&lt;/h1&gt;
&lt;p&gt;There are several different approaches that people use to meet their NER requirements. Generally, these can be broken down into techniques using statistics (including machine learning) and techniques based on grammar. Obviously most implementations take a combination of both of these approaches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More grammar-based techniques involve a higher labour cost but see much more accurate results.&lt;/li&gt;
&lt;li&gt;Statistical approaches produce slightly less accurate results but can analyse sample sets much quicker. A common bottleneck for statistical approaches is the amount of annotated data (these are sentences like in the picture above which are labelled correctly so that the computer can learn how to label too).&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;NERExperimenting&#34;&gt;Experimenting with NER&lt;/h1&gt;
&lt;p&gt;Now that you hopefully have a baseline understanding of what NER is, I could not end this post without suggesting using the NLP package spaCy&amp;rsquo;s NER feature and visualiser (which I even used when making this post)!&lt;/p&gt;
&lt;p&gt;You can find an interactive code playground &lt;a href=&#34;https://spacy.io/usage/linguistic-features#named-entities-101&#34;&gt;here&lt;/a&gt; where you can change anything from the NLP pipeline or just the sentence to analyse.&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Word Vectors Simplified</title>
      <link>https://adamjhawley.com/post/2020-09-04-word-vectors-simplified/</link>
      <pubDate>Fri, 04 Sep 2020 20:53:28 +0300</pubDate>
      
      <guid>https://adamjhawley.com/post/2020-09-04-word-vectors-simplified/</guid>
      
      <description>&lt;blockquote&gt;
&lt;p&gt;Note:
This blog post is based on assignment 1 from the Stanford CS 224N NLP And Deep Learning Course which is available &lt;a href=&#34;http://web.stanford.edu/class/cs224n/index.html#schedule&#34;&gt;here&lt;/a&gt;. I highly recommend this course for people beginning NLP as it is freely available, has great content and is great fun to follow!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ol start=&#34;0&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#word-meaning&#34;&gt;Word Meaning From Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#co-occurrence&#34;&gt;Co-occurrence Matrices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#synonyms&#34;&gt;Synonyms from Vector Similarity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#vector-maths&#34;&gt;Using Vector Maths to Find Semantic Relations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#flat-matrices&#34;&gt;Flattening Matrices for Graphical Representation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Below I hope to outline the concept of word vectors and to show how useful they can be. With the aim of keeping this concise, I will not be discussing implementation details. However these can be found in the course linked at the beginning of this post.&lt;/p&gt;
&lt;p&gt;Word vectors (or word embeddings) are vector representations of the meaning of a given word.&lt;/p&gt;
&lt;h1 id=&#34;word-meaning&#34;&gt;Finding Word Meaning From Surrounding Words&lt;/h1&gt;
&lt;p&gt;Word vectors commonly rely on the fact that words which are commonly found next or close to other words are usually linguistically related (either syntactically or semantically).&lt;/p&gt;
&lt;p&gt;For example, it is natural to think that you would find the word &amp;ldquo;trombone&amp;rdquo; in contexts with a musical theme so you could predict other words which might be in the text such as &amp;ldquo;instrument&amp;rdquo; or &amp;ldquo;song&amp;rdquo;. You would probably also say that it is unlikely that you would find the word &amp;ldquo;kebab&amp;rdquo; around the word &amp;ldquo;trombone&amp;rdquo; because of their very different meanings.&lt;/p&gt;
&lt;p&gt;In real NLP practices, many of the words surrounding a word are used to create a mathematical definition of the word. This number of words is commonly referred to as the &lt;strong&gt;window&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example of an active window when our centre word is &amp;ldquo;snowflakes&amp;rdquo; and with a window size of 1:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://dev-to-uploads.s3.amazonaws.com/i/xqw2fopu7mz8ctrg5k98.png&#34; alt=&#34;Diagram to show active window&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;co-occurrence&#34;&gt;Co-Occurrence Matrices&lt;/h1&gt;
&lt;p&gt;An easy way to represent how frequently words are in the context of other words is to use a &lt;strong&gt;co-occurrence matrix&lt;/strong&gt;. The simple way to think of a co-occurrence matrix is that it is a table where the values are counters of how many times two words &lt;strong&gt;co-occur&lt;/strong&gt;!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;the snowflakes fall from above&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;some raindrops fall from above&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Given the sentences above with a window size 1, we would get the following co-occurrence matrix:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://dev-to-uploads.s3.amazonaws.com/i/dnhlvwgz84gi3yg93irn.png&#34; alt=&#34;Co-occurrence Matrix&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;synonyms&#34;&gt;Synonyms from Vector Similarity&lt;/h1&gt;
&lt;p&gt;Once you have the vector representations of each word calculated, you effectively have vector &lt;em&gt;definitions&lt;/em&gt; for each word. It turns out that you can use vector calculations to interact with these representations. For example, many people learn how to find angles between vectors using &lt;a href=&#34;https://en.wikipedia.org/wiki/Cosine_similarity&#34;&gt;cosine similarity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;$$ similarity = cos(\theta) = \frac{\mathbf{A \cdot B}}{\Vert A \Vert \Vert B \Vert} $$&lt;/p&gt;
&lt;p&gt;The more similar the two vectors, the more closely related the two words are likely to be in meaning.&lt;/p&gt;
&lt;h1 id=&#34;vector-maths&#34;&gt;Using Vector Maths to Find Semantic Relations&lt;/h1&gt;
&lt;p&gt;An interesting find which is discussed in the course practical this is based on, revolves around the difference in vectors and using vector representations to explore relations between words as well as meanings.&lt;/p&gt;
&lt;p&gt;One of the examples uses the the roles of King and Queen and &lt;a href=&#34;https://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.Word2Vec.most_similar&#34;&gt;gensim&amp;rsquo;s most_similar()&lt;/a&gt; to investigate. They show that the difference between man and king should be the same vector difference between queen and woman.
Hence:&lt;/p&gt;
&lt;p&gt;$$ woman + king - man = queen $$&lt;/p&gt;
&lt;h1 id=&#34;flat-matrices&#34;&gt;Flattening Matrices for Graphical Representation&lt;/h1&gt;
&lt;p&gt;Once we have a co-occurrence matrix we can see that the dimensions are too large to display on a standard 2D or 3D graph (and would but much much larger in a practical situation with a corpus consisting of more than 7 words)!&lt;/p&gt;
&lt;p&gt;In order to represent our matrix on a graph we will have to shrink the matrix so that we have appropriate x and y coordinates.&lt;/p&gt;
&lt;p&gt;A popular way to do this is to use &lt;strong&gt;SVD (singular value decomposition)&lt;/strong&gt; .&lt;/p&gt;
&lt;p&gt;Since this post is about keeping it simple I won&amp;rsquo;t go into how SVD works but &lt;a href=&#34;https://ocw.mit.edu/courses/mathematics/18-06sc-linear-algebra-fall-2011/positive-definite-matrices-and-applications/singular-value-decomposition/MIT18_06SCF11_Ses3.5sum.pdf&#34;&gt;here&lt;/a&gt; is a useful resource from MIT on understanding SVD if you want to delve deeper. The key thing for us is that SVD will help us through &lt;em&gt;dimensionality reduction&lt;/em&gt; (going from an n x n matrix to a 2 x n matrix).&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title></title>
      <link>https://adamjhawley.com/archives/</link>
      <pubDate>Tue, 28 May 2019 00:00:00 +0000</pubDate>
      
      <guid>https://adamjhawley.com/archives/</guid>
      
      <description></description>
      
    </item>
    
  </channel>
</rss>

