diff --git a/public/placeholder-about.jpg b/public/placeholder-about.jpg
deleted file mode 100644
index 2f736d92..00000000
Binary files a/public/placeholder-about.jpg and /dev/null differ
diff --git a/public/placeholder-hero.jpg b/public/placeholder-hero.jpg
deleted file mode 100644
index 66c86497..00000000
Binary files a/public/placeholder-hero.jpg and /dev/null differ
diff --git a/public/placeholder-hero.png b/public/placeholder-hero.png
new file mode 100644
index 00000000..1d198217
Binary files /dev/null and b/public/placeholder-hero.png differ
diff --git a/public/placeholder-social.jpg b/public/placeholder-social.jpg
deleted file mode 100644
index e8844fed..00000000
Binary files a/public/placeholder-social.jpg and /dev/null differ
diff --git a/public/placeholder-social.png b/public/placeholder-social.png
new file mode 100644
index 00000000..55568a3c
Binary files /dev/null and b/public/placeholder-social.png differ
diff --git a/src/components/BaseHead.astro b/src/components/BaseHead.astro
index 135d4348..8d08e2b3 100644
--- a/src/components/BaseHead.astro
+++ b/src/components/BaseHead.astro
@@ -1,17 +1,28 @@
---
// Import the global.css file here so that it is included on
// all pages through the use of the component.
-import '../styles/global.css';
+import "../styles/global.css";
export interface Props {
- title: string;
- description: string;
- image?: string;
+ title: string;
+ description: string;
+ image?: string;
+ twitterHandle?: string;
+ author?: string;
+ publishedDate?: string;
}
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
-
-const { title, description, image = '/placeholder-social.jpg' } = Astro.props;
+const defaultDate = new Date().toISOString()
+
+const {
+ author = "Jeremy Wong",
+ description,
+ image = "/placeholder-social.png",
+ title,
+ twitterHandle = "@jermspeaks",
+ publishedDate = defaultDate,
+} = Astro.props;
---
@@ -19,7 +30,7 @@ const { title, description, image = '/placeholder-social.jpg' } = Astro.props;
-
+
@@ -28,6 +39,7 @@ const { title, description, image = '/placeholder-social.jpg' } = Astro.props;
{title}
+
@@ -35,6 +47,11 @@ const { title, description, image = '/placeholder-social.jpg' } = Astro.props;
+
+
+
+
+
@@ -42,3 +59,4 @@ const { title, description, image = '/placeholder-social.jpg' } = Astro.props;
+
diff --git a/src/content/blog/2022-03-01-deno-notes.md b/src/content/blog/2022-03-01-deno-notes.md
new file mode 100644
index 00000000..2de26cc0
--- /dev/null
+++ b/src/content/blog/2022-03-01-deno-notes.md
@@ -0,0 +1,64 @@
+---
+title: "Notes: Deno"
+published: false
+draft: false
+categories: learning
+tags: ["node", "deno"]
+date: 2022-03-01
+description: ""
+pubDate: "2022-03-01"
+heroImage: ""
+postType: "learning"
+---
+
+I am following version 1.13.2: [Intro docs](https://deno.land/manual@v1.13.2/introduction) for Deno
+
+## Hello World
+
+[Tutorial](https://deno.land/manual@v1.13.2/examples/hello_world)
+
+Running the following command in our tutorial folder uses deno as a runtime.
+
+```sh
+deno run 01_hello_world/index.ts
+```
+
+## Import and Exports
+
+[Tutorial](https://deno.land/manual@v1.13.2/examples/import_export)
+
+Local imports use relative paths. Add the extensions.
+
+Remote imports use urls.
+
+Example URL: `https://deno.land/x/ramda@v0.27.2`.
+
+You can find modules on [their website](https://deno.land/x).
+
+Prepend export for constants, classes, functions and variables to expose them.
+
+## Managing dependencies
+
+[Tutorial](https://deno.land/manual@v1.13.2/examples/manage_dependencies)
+
+There are two ways to handle dependencies.
+
+1. Using URL link
+2. Using `deps.ts`
+
+To add a lockfile (useful for locking dependencies), use the `--lock` flag.
+
+```sh
+# Create/update the lock file "lock.json".
+deno cache --lock=lock.json --lock-write deps.ts
+```
+
+[More on integrity checking](https://deno.land/manual@v1.13.2/linking_to_external_code/integrity_checking).
+
+## Fetch data
+
+[Tutorial](https://deno.land/manual@v1.13.2/examples/fetch_data)
+
+## Left Off
+
+- https://deno.land/manual@v1.13.2/examples/manage_dependencies
diff --git a/src/content/blog/2023-02-08-supabase-remix.md b/src/content/blog/2023-02-08-supabase-remix.md
new file mode 100644
index 00000000..25dff889
--- /dev/null
+++ b/src/content/blog/2023-02-08-supabase-remix.md
@@ -0,0 +1,174 @@
+---
+title: "Build a Realtime Chat App with Remix and Supabase"
+published: false
+draft: false
+categories: learning
+tags: ["supabase", "remix", "react"]
+date: 2023-02-08
+description: "From an egghead course, notes about building a realtime chat app with remix and supabase"
+pubDate: "2023-02-08"
+heroImage: ""
+postType: "learning"
+---
+
+The following are notes from an Egghead [course](https://egghead.io/courses/build-a-realtime-chat-app-with-remix-and-supabase-d36e2618?_cio_id=89fb05009d5c9e5c&utm_campaign=Round%202%20-%20Build%20a%20realtime%20chat%20app%20with%20Remix%20and%20Supabase&utm_content=Build%20a%20realtime%20chat%20app%20with%20Remix%20and%20Supabase&utm_medium=email_action&utm_source=customer.io) I took.
+
+## Create a Supabase Project with a Table and Example Data
+
+- Created a new database on supabase called [Chatter](https://app.supabase.com/project/akhdfxiwrelzhhhofvly)
+- In the table editor, create a new table `messages`, and add columns for `id`, `created_at`, and `content`.
+ - `id` should be a uuid
+ - `created_at` should default `now()` and never be null
+ - `content` is text and should never be null
+
+## Setting Up a Remix Project
+
+- Create a new remix project
+ - Choose "Just the basics"
+ - Choose Vercel as the service
+
+```sh
+npx create-remix chatter
+```
+
+- For the remix project, you can find the main file in `index.tsx`
+
+## Query Supabase Data with Remix Loaders
+
+- `npm i @supabase/supabase-js`
+- Add supabase env vars to .env, which can be found in the _Project Settings > API_. [Link](https://app.supabase.com/project/akhdfxiwrelzhhhofvly/settings/api)
+
+```
+SUPABASE_URL={url}
+SUPABASE_ANON_KEY={anon_key}
+```
+
+- Create a `utils/supabase.ts` file. Create `createClient` function
+- A "!" can be used at the end of a variable so typescript doesn't give us errors, if we know those will be available at runtime, like env vars
+- Supabase has row-level security enabled, meaning you have to write policies in order for the user to do CRUD operations (`SELECT`, `INSERT`, `UPDATE`, `DELETE`, and `ALL`).
+ - We added a policy to allow all users to read.
+- Create the loader in the index page, using `import { useLoaderData } from "@remix-run/react";`, which will allow us to query supabase using the utils.
+ - `supabase.from("messages").select()` reminds me a lot like mongodb's client.
+
+## Generate TypeScript Type Definitions with the Supabase CLI
+
+- Add Type Safety checks using the [Supabase CLI](https://supabase.com/docs/guides/cli)
+
+```sh
+brew install supabase/tap/supabase
+# Or call upgrade if you already have it
+brew upgrade supabase
+```
+
+- [Create an account token](https://app.supabase.com/account/tokens)
+ - Then login to CLI tool using that access token
+
+```sh
+supabase login
+```
+
+- Generate types based our project for Typescript
+
+```sh
+supabase gen types typescript --project-id akhdfxiwrelzhhhofvly > db_types.ts
+```
+
+- We have to re-run this command every time we have DB updates
+- Now we use the `db_types.ts` into our `supabase.ts` file by adding a type to the `createClient` function
+- You can infer types by using `typeof` in Typescript. This is useful for showcasing what `data`'s type is in the `Index` functional component.
+- To make sure the data is always present, or an empty array rather than of type `null`, we use a null coalescing operator on the original data `return { messages: data ?? [] };`
+
+## Implement Authentication for Supabase with OAuth and Github
+
+- Enable Github OAuth using Supabase
+ - In the supabase project, go to Authentication > Providers
+ - Choose Github
+- In Github, go to Settings, Developer Settings > OAuth Apps
+ - Create "Chatter". Copy the Authorization callback URL
+- In supabase, enter the Client ID, Client Secret, and the Redirect URL.
+ - The generated secret in Github goes away after a few minutes, so be quick
+- Create the login component in `components/login` and then add two buttons for logging in and out.
+ - The handlers should be `supabase.auth.signInWithOAuth` and `supabase.auth.signOut`
+- Add the login component back into the index component.
+ - You'll notice a `ReferenceError` in that `process` is not defined because that should only run on the server.
+ - Change the `supabase.ts` file to `supabase.server.ts` file. This shows that the supabase file should only be rendered on the server.
+ - The `root.tsx` component has an `Outlet` depending on the route based off the `routes` files (file-based routing)
+- In the root component, we add the context in `Outlet` for the supabase instance.
+ - This can now be used in the `login` file using `useOutletContext`.
+ - Types can be added by exporting it from root.
+ - `type TypedSupabaseClient = SupabaseClient;`
+- supabase uses Local Storage to store the OAuth tokens.
+ - You can also check [the users](https://app.supabase.com/project/akhdfxiwrelzhhhofvly/auth/users) in the supabase project
+
+## Restrict Access to the Messages Table in a Database with Row Level Security (RLS) Policies
+
+- Add a column to our database called `user_id` and add a foreign key to it, with `users` and the key being `id`.
+- Disable _Allow Nullable_ by adding the logged in user id to the first two messages. This can be found in the users table.
+- Re-run the db_types script
+
+```sh
+supabase gen types typescript --project-id akhdfxiwrelzhhhofvly > db_types.ts
+```
+
+- Update the policy by changing the target roles to be authenticated.
+- Now only signed in users will be able to view the data.
+
+## Make Cookies the User Session Single Source of Truth with Supabase Auth Helpers
+
+- Auth tokens by default are stored in the client's session, not on the server.
+ - Remix is loading from the server's session, which is null
+- `npm i @supabase/auth-helpers-remix`
+- We need to change the mechanism for the token to use cookies
+ - Auth helpers allows us to use `createServerClient` and `createBrowserClient` to create the supabase instance correctly, based if it's on the client or server.
+ - You need `request` and `response` added in the `supabase.server.ts`
+ - We need to do the same thing in the loader in `root` and `index`
+
+## Keep Data in Sync with Mutations Using Active Remix Loader Functions
+
+- There's no update for pressing the button because the client doesn't update the information after the initial load.
+- Remix has a revalidation hook.
+- Supabase has a auth state change hook
+ - Combining these together, on server and client token change (either new token, or no longer has the token), then refetch data from loaders.
+
+## Securely Mutate Supabase Data with Remix Actions
+
+- To create a new message, we add `Form` from remix, which has a method `post`.
+ - This is reminiscent of how forms worked alongside the HTML spec before
+- An action is created to insert the message, include the response headers from before (passing along the cookie)
+- The message won't send yet until the supabase policy is set, so we add a policy for `INSERT` and make sure the user is authenticated and their user_id matches the one in supabase.
+
+## Subscribe to Database Changes with Supabase Realtime
+
+- Supabase sends out updates via websockets when there is a change to the database
+ - It's called [Replication](https://app.supabase.com/project/akhdfxiwrelzhhhofvly/database/replication)
+- We create a new component, `RealtimeMessages` that can subscribe to those `INSERT` changes on all tables
+ - We set messages in a `useState` hook, and any changes we will change them with a `useEffect`
+ - A second `useEffect` subscribes to these supabase changes
+
+```ts
+const channel = supabase
+ .channel("*")
+ .on(
+ "postgres_changes",
+ { event: "INSERT", schema: "public", table: "messages" },
+ (payload) => {
+ const newMessage = payload.new as Message;
+
+ if (!messages.find((message) => message.id === newMessage.id)) {
+ setMessages([...messages, newMessage]);
+ }
+ }
+ )
+ .subscribe();
+```
+
+## Deploy a Remix Application to Vercel from a GitHub Repository
+
+- Create a Github repo
+ - There's a [Github CLI tool](https://cli.github.com/), `gh`, that can handle this
+ - `gh repo create chatter --public`
+- Init the repo, commit, and push
+- Go to Vercel, add the project and env variables
+- Go to Github and add the redirect URL
+- Go to Supabase and add authentication url redirect
+- [Final URL](https://chatter-omega.vercel.app/?index)
diff --git a/src/content/blog/2023-04-15-notes-agi.md b/src/content/blog/2023-04-15-notes-agi.md
new file mode 100644
index 00000000..034f9a17
--- /dev/null
+++ b/src/content/blog/2023-04-15-notes-agi.md
@@ -0,0 +1,113 @@
+---
+category: blog
+date: 2023-04-15
+description: "An exercise where I lay out my favorite questions. These questions are long-term problems without easy answers."
+draft: false
+heroImage: ""
+postType: "blog"
+pubDate: "2023-04-15"
+title: "AI Notes for Developers"
+tags: ["reflections"]
+---
+
+## Practical AI for Developers
+
+### Command Line
+
+- [Warp](https://www.warp.dev/) command line tool w/ AI capabilities
+
+### Coding
+
+- Co-pilot and code augmentation
+ - Initially from OpenAI's fine-tuned GPT-3 version called [Codex](https://arxiv.org/abs/2107.03374)
+ - AI-powered Code Generation, a smarter text expansion
+ - Trained on open source code from Github
+ - Reinforcement learning means it gets better with time, but maybe just incrementally
+ - Prompt Engineering
+ - Surprising use cases
+ - Giving enough in the comments for generate decent code. Still needs some analysis
+ - Giving a template for unit tests.
+ - A lot of times, developers skip this step. By having an outline for it, the time to write tests go down
+ - AI-powered tools as paired programming
+ - Great alternative to the question and answer sites like StakeOverflow
+- Limitations
+ - Answers are generative, meaning what you use in the prompt and how the model was training will determine the output
+ - If you are looking for structured data, Google and Wolfram|Alpha do a much better job
+ - ![Wolfram Alpha showcasing GPT](https://content.wolfram.com/uploads/sites/43/2023/01/ChatGPT-hero-v4.png)
+ - Code that's complexity is still hard to write
+ - Can get very buggy
+ - Training models in a rut w/ a Glitch Token
+ -
+ - SMEs need to be the adult in the room
+ - Legality
+ > A class-action lawsuit against GitHub, OpenAI, and Microsoft claims that the training of Codex violated open source licensing agreements. The outcome could have legal implications for models that generate text, images, and other media as well.
+ - [We Ask a Lawyer about Github Copilot](https://changelog.com/podcast/458)
+ - [NeoVim plugin](https://github.com/github/copilot.vim)
+- Other tools
+ - [AlphaCode](https://www.deeplearning.ai/the-batch/competitive-coder/)
+ - Ebay's [low-code AI](https://www.protocol.com/enterprise/ebay-ai-mekel-bobrov?utm_campaign=The%20Batch&utm_source=hs_email&utm_medium=email)
+- Low-code scripting
+ - Alternative to writing your own code for general scripting
+ - For example, [Google App Scripts](https://www.google.com/script/start/)
+ -
+
+## Researching tools
+
+- Feedback from Chuks about learning new topics
+- Notemaking - https://fireflies.ai/
+ - Summarizing meetings, take action items, etc.
+- https://www.producthunt.com/topics/artificial-intelligence
+- PR Reviewer powered with GPT models
+
+## Reading
+
+- [Ghostreader](https://readwise.io/read) from Readwise Reader that helps augment reading
+ - Like Shortform or Blinkest, as a pair next to you
+ - Doesn't replace reading, but good at summarizing what you are reading and some questions to help with critical thinking
+- Reading resumes
+ - Could it give you resume quality back?
+- Summarizer
+ - Brave Search summarizer
+ - Bing search summaries
+ - Readwise Reader ghostreader
+
+## Writing
+
+- Emails
+- Resumes
+- Cover Letters
+- Slack messages?
+- Brainstorming
+- Wiki Pages, blog posts, meeting agenda, social media, PRs, Job descriptions, sales emails, poems, pros and cons lists, outlines
+ - [Notion AI](https://www.notion.so/product/ai) can handle a first draft
+- Technology matricies
+- Tools
+ - Notion AI
+ - Lex
+- Obsidian forum has [users ideating what AI could look like]([AI Assisted Q&A / Chatbot / Text Generation](https://forum.obsidian.md/t/ai-assisted-q-a-chatbot-text-generation/56014)) for the app
+ - [Learning to summarize with human feedback](https://openai.com/research/learning-to-summarize-with-human-feedback)
+ - ![Summarizing using human feedback](https://openaicom.imgix.net/c8746ba3-7546-4492-8d1e-f7ec6dbae5e0/approach.svg?fm=auto&auto=compress,format&fit=min&w=3840&h=1982)
+
+## Reflecting on different applications for AGI
+
+- Deep Learning's newsletter, "The Batch", reflected on [the general uses and stories for 2022](https://www.deeplearning.ai/the-batch/issue-176/).
+ - Synthetic Images
+ - New technologies
+ - [[OpenAI]]'s DALL·E 2
+ - [Stable Diffusion](https://stability.ai/blog/stable-diffusion-public-release)
+ - Prompt Engineering arises
+ - Places like [PromptBase](https://www.deeplearning.ai/the-batch/prompting-dall-e-for-fun-and-profit/) are an open marketplace for text strings that generate interesting output
+ - Limitations
+ - Training set based off online images, which have inherit biases (see bad algorithms)
+ - For example, sexualizing women unfairly
+ - Concerns
+ - Concern with legality
+ - Concern with artists
+ > ArtStation, an online community for visual artists, launched its own text-to-image features. Many artists, feeling threatened by computer programs that can reproduce an artist’s hard-won personal style in seconds, boycotted the website.
+ - Things I still don't understand
+ - GAN - Generative Adversarial Networks
+ - [Prompt Engineering is Probably More Important Than You Think](https://thealgorithmicbridge.substack.com/p/prompt-engineering-is-probably-more?utm_source=substack&utm_medium=email)
+ - Current LLMs provide windows into their process through prompts
+ - In the future, we may have something more precise
+ - In the interim, we have prompts to guide us through the _alien_ silicon
+- Knowledge Base Q&A
diff --git a/src/content/blog/markdown-style-guide.md b/src/content/blog/markdown-style-guide.md
index 261ecc0c..d5053569 100644
--- a/src/content/blog/markdown-style-guide.md
+++ b/src/content/blog/markdown-style-guide.md
@@ -2,7 +2,7 @@
title: "Markdown Style Guide"
description: "Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro."
pubDate: "Jul 01 2022"
-heroImage: "/placeholder-hero.jpg"
+heroImage: "/placeholder-hero.png"
draft: true
postType: "template"
---
@@ -33,7 +33,7 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
## Images
-![This is a placeholder image description](/placeholder-social.jpg)
+![This is a placeholder image description](/placeholder-social.png)
## Blockquotes
diff --git a/src/content/blog/using-mdx.mdx b/src/content/blog/using-mdx.mdx
index 9e3de631..3091fc8b 100644
--- a/src/content/blog/using-mdx.mdx
+++ b/src/content/blog/using-mdx.mdx
@@ -2,7 +2,7 @@
title: 'Using MDX'
description: 'Lorem ipsum dolor sit amet'
pubDate: 'Jul 02 2022'
-heroImage: '/placeholder-hero.jpg'
+heroImage: '/placeholder-hero.png'
draft: true
postType: "template"
---