Compare commits

..

No commits in common. "997c36855c996f500959e223c814ebcfa4618025" and "77232e4af337d13901bfb921b8d4e946d6c7b82b" have entirely different histories.

183 changed files with 1194 additions and 3005342 deletions

3
.gitattributes vendored
View file

@ -1 +1,2 @@
static/files/images/tracks/** filter=lfs diff=lfs merge=lfs -text static/files/images/tracks/ filter=lfs diff=lfs merge=lfs -text
static/files/images/tracks filter=lfs diff=lfs merge=lfs -text

View file

@ -37,12 +37,27 @@ jobs:
- name: Setup Hugo - name: Setup Hugo
env: env:
HUGO_VERSION: 0.143.1 HUGO_VERSION: 0.105.0
run: | run: |
curl -L "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz" --output hugo.tar.gz curl -L "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz" --output hugo.tar.gz
tar -xvzf hugo.tar.gz tar -xvzf hugo.tar.gz
sudo mv hugo /usr/local/bin sudo mv hugo /usr/local/bin
- name: Install Rust
run: |
sudo apt update
sudo apt install -y rustc cargo
- name: Build Website-Toots
run: |
cd content/toots/.scripts
cargo build --release
- name: Pre-build script
run: |
./build.sh
- name: Build Hugo Website - name: Build Hugo Website
id: build id: build
run: | run: |
@ -53,11 +68,10 @@ jobs:
install -m 600 -D /dev/null ~/.ssh/id_rsa install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.BUILD_SSH_KEY }}" > ~/.ssh/id_rsa echo "${{ secrets.BUILD_SSH_KEY }}" > ~/.ssh/id_rsa
echo "${{ secrets.HOST_KEY }}" > ~/.ssh/known_hosts echo "${{ secrets.HOST_KEY }}" > ~/.ssh/known_hosts
cat <<EOL > ~/.ssh/config echo "Host brandonrozek.com
Host Rozek-Fog Hostname brandonrozek.com
Hostname 208.99.44.108 user build
User build IdentityFile ~/.ssh/id_rsa" > ~/.ssh/config
IdentityFile ~/.ssh/id_rsa
EOL
- name: Deploy - name: Deploy
run: ./deploy.sh run: ./deploy.sh

8
.gitmodules vendored
View file

@ -2,3 +2,11 @@
path = themes/pulp path = themes/pulp
url = git@github.com:Brandon-Rozek/website-theme.git url = git@github.com:Brandon-Rozek/website-theme.git
branch = master branch = master
[submodule "content/toots"]
path = content/toots
url = git@github.com:Brandon-Rozek/website-toots.git
branch = main
[submodule "content/observations"]
path = content/observations
url = git@github.com:Brandon-Rozek/website-observations.git
branch = main

17
build.sh Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Generate toot markdown files
pushd content/toots/.scripts > /dev/null
generate_exe="./target/release/generate_md"
# Check if the file exists and is executable
if [ -e "$generate_exe" ] && [ -x "$generate_exe" ]; then
./target/release/generate_md
else
echo "The executable '$generate_exe' does not exist."
echo "Perhaps run cargo build in 'content/toots/.scripts'?"
fi
popd > /dev/null

View file

@ -4,9 +4,6 @@ title = "Brandon Rozek"
theme = "pulp" theme = "pulp"
enableGitInfo = true enableGitInfo = true
[security.http]
mediaTypes = ['^application/json']
[taxonomies] [taxonomies]
series = "series" series = "series"
tags = "tags" tags = "tags"
@ -18,7 +15,7 @@ mediaTypes = ['^application/json']
author = "Brandon Rozek" author = "Brandon Rozek"
avatar = "avatar.jpg" avatar = "avatar.jpg"
favicon = "favicon.ico" favicon = "favicon.ico"
description = "PhD Student @ RPI, Writer of Tidbits, and Linux Enthusiast" description = "PhD Student @ RPI studying Automated Reasoning in AI and Linux Enthusiast."
email = "brozek@brandonrozek.com" email = "brozek@brandonrozek.com"
identities = [ identities = [
"https://github.com/brandon-rozek", "https://github.com/brandon-rozek",
@ -88,13 +85,6 @@ mediaTypes = ['^application/json']
url = "/research/" url = "/research/"
weight = 20 weight = 20
[[menu.main]]
identifier = "postroll"
name = "Postroll"
pre = "<i class='fas fa-scroll'></i>"
url = "/postroll"
weight = 30
[[menu.main]] [[menu.main]]
identifier = "community" identifier = "community"
name = "Community" name = "Community"
@ -102,12 +92,7 @@ mediaTypes = ['^application/json']
url = "/community/" url = "/community/"
weight = 40 weight = 40
[[menu.profile]]
identifier = "email"
name = "Email"
pre = "<i class='fa fa-envelope fa-lg'></i>"
url = "mailto:brozek@brandonrozek.com"
weight = 75
[[menu.profile]] [[menu.profile]]
identifier = "mastodon" identifier = "mastodon"
@ -122,3 +107,18 @@ mediaTypes = ['^application/json']
pre = "<i class='fab fa-github fa-lg'></i>" pre = "<i class='fab fa-github fa-lg'></i>"
url = "https://github.com/brandon-rozek" url = "https://github.com/brandon-rozek"
weight = 85 weight = 85
[[menu.profile]]
identifier = "scholar"
name = "Google Scholar"
pre = "<i class='fas fa-graduation-cap'></i>"
url = "https://scholar.google.com/citations?user=JrgtnwgAAAAJ&hl=en&oi=ao"
weight = 90
[[menu.profile]]
identifier = "email"
name = "Email"
pre = "<i class='fa fa-envelope fa-lg'></i>"
url = "mailto:brozek@brandonrozek.com"
weight = 95

View file

@ -2,4 +2,3 @@
title: Brandon Rozek title: Brandon Rozek
description: "Software Developer, Researcher, and Linux Enthusiast." description: "Software Developer, Researcher, and Linux Enthusiast."
--- ---

View file

@ -1,106 +0,0 @@
---
title: "10 Years"
date: 2025-04-16T12:13:29-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
On April 16 2015, I wrote my first two [blog](/blog/2015-04-16-function-two-points-theory/) [posts](/blog/2015-04-16-responsive-layout-and-animation/) on creating responsive layouts in CSS. It's crazy to think that I still have this blog going after 10 years. Since then I've lived in 9 different places, worked at 6 different organizations, and got to meet many wonderful people including my now fiance.
I thought it would be nice to look back over the last ten years, and talk about my favorite blog posts of each year. What I've come to realize in this exercise is that I really came a long way. I mean, it's not that hard to beat my first blog post where I just scanned a sheet of paper!
*Disclaimer:* Posts before mid-2019 were on Wordpress, and let's just say that the migration to Hugo hasn't been perfect...
## 2015
**Favorite Post:** [Limiting the cache in Service Workers Revisited](/blog/2015-11-30-limiting-cache-service-workers-revisited3/)
Service workers was one of the first ways you can have persistent background processing on a website. From my memory, the big use case was that you can get social media notifications without even having the tab open. I'm not sure how, but I ended up on the bleeding edge of this since it was first fully released on Chrome without a feature flag September 2015.
While we all love getting notifications, a more interesting use case to us in the blogging community was that you can use service workers to make your website available offline! I wrote about [how to do so](/blog/2015-11-14-service-workers/) and then wrote this update a few weeks later to help address a [caching](https://adactio.com/journal/9844) [issue](https://adactio.com/journal/9888) that Jeremy Keith identified.
## 2016
**Favorite Post:** [Pass the password manager](/blog/2016-08-16-pass-password-manager/)
This is the only blog post I wrote in 2016 so it wins by default. At the time, I used the CLI application [`pass`](https://www.passwordstore.org/) to manage my passwords and [Syncthing](https://syncthing.net/) to share it between devices. Nowadays, I entrust [Bitwarden](https://bitwarden.com/) when it comes to handling my passwords.
## 2017
**Favorite Post:** [Approximating Pi using a Monte Carlo Simulation](/blog/2017-03-14-monte-carlo-pi/)
2017 was the year that I got really into statistics and approximation. Not only was I approximating Pi like above, but I was also testing the [randomness of random number generators](https://brandonrozek.com/blog/2017-03-07-uniformity-math-random/), looking at [male vs female life expectancy](https://brandonrozek.com/blog/male-vs-female-life-expectancy/), and building a regression model of the [price of homes in Albuquerque, New Mexico](https://brandonrozek.com/blog/albuquerque/).
Nowadays I don't work with Statistics as often. However, I do think it's cool how we can come up with models to attempt to describe how the world works even when we don't have much data available.
Also being able to make approximations with [Monte-Carlo methods](/research/reinforcementlearning/notes/mcmethods/), and resampling techniques like [bootstrapping](https://github.com/Brandon-Rozek/bootstrapr) is awesome.
## 2018
**Favorite Post:** [Identifying Misspelled Words in your Dataset with Hunspell](/blog/2018-01-22-identifying-misspelled-words-dataset-hunspell/)
Similar to 2016, this is the winner by default since it's the only blog post I wrote that year. I'm happy that I don't currently have to deal with data cleaning.
## 2019
**Favorite Post:** [Capture The Flag](/blog/ctf/)
From this point on, it only gets harder for me to select my favorite! For the first four years I only wrote 30 blog posts total. In the year 2019, I wrote 60! If I had to chose, my favorite would be when I briefly described the challenges I made for a capture the flag competition during my undergraduate days. I also really enjoyed encoding [mathematical](/blog/pythonsymmetricgroups/) [problems](/blog/haskellrealsequences/) in code.
## 2020
**Favorite Post:** [Disk Golf and PyMC3](https://brandonrozek.com/blog/discgolfpymc/)
Somehow in 2020 I wrote 128 blog posts. Many of them are short tidbits of things I've learned. But still, that's almost a blog post every 3 days! According to my [stats page](/stats) this is the current record of blog posts per year by far. We'll see if I ever beat this record.
My favorite out of this batch is a blog post that's a combination of personal life and statistics. In a semi-competitive semi-joking way, I wanted to determine who was the best at disk golf between Clare, Chris, and I based on just one outing. After performing some Bayesian magic, I found that Chris and I pretty much have the same performance (ignore the 0.2 score difference) and Clare is sadly worse than the both of us.
Other great pieces that year was my blog post on [Cryptographic Games](/blog/cryptogames/) and [Tail call optimization in Python](/blog/tcopython/).
## 2021
**Favorite Post:** [Introduction to RF Power Amplifiers](/blog/introrfpoweramp/)
Before I stopped actively pursuing Amateur radio, I wanted to write some notes in case I ever get back into the hobby. Turns out, radio waves are based on electricity and life is a lot easier if you have an electrical engineering degree to understand all of the terminology used.
That doesn't mean you need a degree to get in the hobby though! In the US, you'll need to at least have a technicians license to get on the air and luckily all the questions and answers for the exam are [available online](https://hamexam.org/). After getting licensed, you can pick up a UHF/VHF radio for $20 and chat with anybody on a [local repeater](https://www.repeaterbook.com/repeaters/).
Though the reason I got into the hobby is that it can be as complicated as you want. At the time I was highly interested in digital modes and software defined radios. This blog post came about as I was trying to figure out what I needed to buy for the annual [Amateur Radio Field Day](https://en.wikipedia.org/wiki/Field_Day_%28amateur_radio%29).
## 2022
**Favorite Post:** [Finding Cool People on Mastodon](/blog/finding-cool-people-on-mastodon/)
On August 2022, I joined Mastodon and like all new people had to figure out where all the cool folks are. I'm not often on Mastodon nowadays, but it's awesome that an open-source microblogging platform has gotten popular.
This was also the year I introduced the [tracks](/tracks) feature on my website. I really enjoy going on walks, and having a section of my website that shows where I walked and the pictures along the way is wicked cool. I fully described the implementation of this feature in the post [Displaying Hikes with gpx.studio](/blog/displaying-hikes-with-gpxstudio/).
Lastly, professionally I was a teaching assistant. A couple posts were born from seeing student mistakes. My favorites were [Loop Invariants in Dafny](/blog/proving-loop-invariants/) and [Most Common Mistake in Induction Proofs](/blog/common-mistake-induction-proofs/).
## 2023
**Favorite Post:** [Adventures in Bird Watching](/blog/adventures-in-bird-watching/)
In 2021 I wrote a blog post comparing different RF power amplifiers. Similarly in 2023, I wrote about what considerations you need to make when buying binoculars for bird watching. I never fully got into bird watching as a hobby, but I encourage you to go on a bird tour at least once if you're able. It's fun to learn about the birds that fly above you and live in the trees near you.
I don't often give glimpses of my life, but I shared a [trip to Brooklyn](/blog/day-in-brooklyn/) that Clare and I did with my brother. In terms of more technical posts, I wrote about [functional completeness](/blog/functional-completeness/) and an alternative way of [representing uncertainty under the closed world assumption](/blog/representing-uncertainty-closed-world-assumption/).
Since I work on multiple devices, I make more merge conflicts than I like to admit. I wrote a small script to tell me whether the git repository I'm working on is [ahead or behind](/blog/ahead-behind-git/) the remote one. Lastly, for many years I've used Syncthing to synchronize my files between my devices. By default it uses public relays and public discovery services, however, I run my own servers so why not use that instead? I describe my setup in the blog post [How to set up a private syncthing network](/blog/private-syncthing-network/).
## 2024
**Favorite Post:** [Hashing Based on Word (Emoji?) Lists](/blog/hashing-based-on-word-emoji-lists/)
In contrast to what I said in the [blog questions challenge](/blog/blog-question-challenge-jan2025/), my favorite blog post last year was one where I wrote a hash function based on an Emoji list. I don't use emojis nearly enough in my daily life and there's more than 5042 of them to chose from!
Winters here in New York is cold and I often don't want to go outside. One of the events I look forward to is watching my university's hockey games. Therefore a close second place for last year is when I wrote about my [experience watching ice hockey](/blog/ice-hockey/). Another yearly tradition of Clare and I is to go [Apple Picking](/blog/hunter-gathering-apple-picking/) in the fall.
In terms of software, I wrote about a way you can [access your homelab remotely using mTLS](/blog/accessing-homelab-services-mtls/). Also, I really appreciate the mission of the [Tildeverse](/blog/tildeverse/) and last year wrote [WordGuess: A game for the Tildeverse](/blog/wordguess/). Lastly, my favorite writeup related to my research last year is [Constraints and Safety in PDDL](/blog/safety-constraints-pddl/)
## Conclusion
That's a wrap! We're too early in the year 2025 for me to pick, as I've only written five blog posts so far.
Here's to another 10 years and as always feel [free to get in touch](/contact/).

View file

@ -17,7 +17,6 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["Web", "CSS"] tags: ["Web", "CSS"]
math: true
--- ---
I saw [Mike Riethmuller&#8217;s](http://madebymike.com.au/) precision typography [pen](http://codepen.io/MadeByMike/pen/YPJJYv){.broken_link}, and was highly impressed. I think the equation used has other purposes as well I saw [Mike Riethmuller&#8217;s](http://madebymike.com.au/) precision typography [pen](http://codepen.io/MadeByMike/pen/YPJJYv){.broken_link}, and was highly impressed. I think the equation used has other purposes as well
@ -27,13 +26,7 @@ Side Note: I changed the form of the equation to something similar to y = mx + b
#### Responsive Layout #### Responsive Layout
There are many occasions where I want an element on the page to move between two points. The navigation in the header of my site (at the time of writing) is a great example of this. So knowing the two points I want it to lie between and having the screen width as the variable, I can plug in: There are many occasions where I want an element on the page to move between two points. The navigation in the header of my site (at the time of writing) is a great example of this. So knowing the two points I want it to lie between and having the screen width as the variable, I can plug in&#8230; [<img class="aligncenter size-full wp-image-58" src="https://brandonrozek.com/wp-content/uploads/2015/04/responsivelayoutequation.gif" alt="f(x) = (100 * (b - a)/(d - c))X + (ad - bc) / (d - c)" width="219" height="36" />](https://brandonrozek.com/wp-content/uploads/2015/04/responsivelayoutequation.gif){.broken_link} where a is the start pixel b is the end pixel c is the start media query d is the end media query and X is the screen width out of 100 otherwise known as 1vw \*\*Don&#8217;t forget to keep track of your units!! Whether it&#8217;s px/rem/em/etc.\*\* Say I want to push a box towards the right a minimum of 5px, a maximum of 20px and for the push to vary between the widths 400-800px. Then I would write&#8230;
$$$
f(x) = (100 * (b - a)/(d - c))X + (ad - bc) / (d - c)
$$$
where a is the start pixel b is the end pixel c is the start media query d is the end media query and X is the screen width out of 100 otherwise known as 1vw \*\*Don't forget to keep track of your units!! Whether it's px/rem/em/etc.\*\* Say I want to push a box towards the right a minimum of 5px, a maximum of 20px and for the push to vary between the widths 400-800px. Then I would write&#8230;
```css ```css
@media (min-width: 400px) and (max-width: 800px) { @media (min-width: 400px) and (max-width: 800px) {
@ -69,19 +62,12 @@ That would only make it vary between 400-800px. Now we need to include what happ
} }
``` ```
This is exactly like Mike's pen, but instead he uses the equation to adjust the font-size between an upper and lower bound. You can apply this method to anything that accepts calc() and viewport units. Here is my [pen](http://codepen.io/brandonrozek/pen/JoQVEb){.broken_link} showing some use cases. To make your life easier, I made a quick little tool where you can input the variables and it will provide you with a simpler form of the equation to put into your calc() function [here](http://codepen.io/brandonrozek/pen/KpPwGL){.broken_link}. This is exactly like Mike&#8217;s pen, but instead he uses the equation to adjust the font-size between an upper and lower bound. You can apply this method to anything that accepts calc() and viewport units. Here is my [pen](http://codepen.io/brandonrozek/pen/JoQVEb){.broken_link} showing some use cases. To make your life easier, I made a quick little tool where you can input the variables and it will provide you with a simpler form of the equation to put into your calc() function [here](http://codepen.io/brandonrozek/pen/KpPwGL){.broken_link}.
#### Animation #### Animation
This is where the majority of my research went towards. It's not as practical as say positioning an element is but I find it interesting. Like, what if I can manipulate the acceleration of the function? This is where the majority of my research went towards. It&#8217;s not as practical as say positioning an element is but I find it interesting. Like, what if I can manipulate the acceleration of the function? [<img class="aligncenter size-full wp-image-62" src="https://brandonrozek.com/wp-content/uploads/2015/04/accelerationequation.gif" alt="f(x) = ((b - a) / (d^n - c^n))X^n + (ad^n - bc^n) / (d^n - c^n) " width="202" height="36" />](https://brandonrozek.com/wp-content/uploads/2015/04/accelerationequation.gif){.broken_link} Where a is the start unit b is the end unit c is the start time d is the end time n is the acceleration modifier and X is time The interesting part of the function here is the n. If I keep n at 1, then the acceleration is constant. If it&#8217;s less than one, then it&#8217;s fast in the beginning and slows down at the end. If it&#8217;s greater than one, then it&#8217;s the opposite. I also made a little pen [here](http://codepen.io/brandonrozek/pen/RNzdOV){.broken_link} to demo this for you.
$$$
f(x) = ((b - a) / (d^n - c^n))X^n + (ad^n - bc^n) / (d^n - c^n)
$$$
Where a is the start unit b is the end unit c is the start time d is the end time n is the acceleration modifier and X is time The interesting part of the function here is the n. If I keep n at 1, then the acceleration is constant. If it's less than one, then it's fast in the beginning and slows down at the end. If it's greater than one, then it's the opposite. I also made a little pen [here](http://codepen.io/brandonrozek/pen/RNzdOV) to demo this for you.
#### Conclusion #### Conclusion
Having a function that goes between two points is incredibly handy. Now when it comes to positioning, I don't have to guess which values match the design. If i cant something to be between here and there fluidly, I can do it. What about animation? Chaining them together should have an interesting affect&#8230; P.S For those of you crazy people who like to see the theory behind the math, (like myself) I have my scanned work [here](/blog/2015-04-16-function-two-points-theory/). Having a function that goes between two points is incredibly handy. Now when it comes to positioning, I don&#8217;t have to guess which values match the design. If i cant something to be between here and there fluidly, I can do it. What about animation? Chaining them together should have an interesting affect&#8230; P.S For those of you crazy people who like to see the theory behind the math, (like myself) I have my scanned work [here](/blog/2015-04-16-function-two-points-theory/).

View file

@ -18,11 +18,11 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["Web", "CSS"] tags: ["Web", "CSS"]
--- ---
This is part 1 of an animation series I'm doing. It is inspired by Lea Verou's talk called &#8220;[The Humble Border-Radius.](https://www.youtube.com/watch?v=JSaMl2OKjfQ)&#8221; I looked at her site and she has a good demo of a bunch of different animations [here](http://lea.verou.me/2011/10/animatable-a-css-transitions-gallery/). My goal here is to create a more comprehensive guide to these different animatable properties&#8211;mainly for future reference. Animations play a big part in adding interactivity to the web, so why not explore some possible options? This is part 1 of an animation series I&#8217;m doing. It is inspired by Lea Verou&#8217;s talk called &#8220;[The Humble Border-Radius.](https://www.youtube.com/watch?v=JSaMl2OKjfQ)&#8221; I looked at her site and she has a good demo of a bunch of different animations [here](http://lea.verou.me/2011/10/animatable-a-css-transitions-gallery/). My goal here is to create a more comprehensive guide to these different animatable properties&#8211;mainly for future reference. Animations play a big part in adding interactivity to the web, so why not explore some possible options?
<!--more--> <!--more-->
This post follows well along with my Codepen [demo](http://codepen.io/brandonrozek/full/waWMWR/){.broken_link}, where I'll state the box number that applies to what I'm talking about. \*\*Initial values must be explicitly stated, implicit initial values are generally ignored in animation\*\* \*\\*\*In English terms, you must have already stated a value for what you are animating before you animate it\*\** This post follows well along with my Codepen [demo](http://codepen.io/brandonrozek/full/waWMWR/){.broken_link}, where I&#8217;ll state the box number that applies to what I&#8217;m talking about. \*\*Initial values must be explicitly stated, implicit initial values are generally ignored in animation\*\* \*\\*\*In English terms, you must have already stated a value for what you are animating before you animate it\*\**
### Border-color {#border-color} ### Border-color {#border-color}
@ -30,7 +30,7 @@ This post follows well along with my Codepen [demo](http://codepen.io/brandonroz
* Each value corresponds to each side of the border (starting from the top and going clockwise) * Each value corresponds to each side of the border (starting from the top and going clockwise)
* Initial Value: currentColor * Initial Value: currentColor
Border-color animates by splitting the colors to their red, green and blue components and raises/lowers them to its new value. ([Demo](http://codepen.io/brandonrozek/pen/PqzPMe){.broken_link}) ([Spec](http://www.w3.org/TR/css3-transitions/#animtype-color)) Example of animation corresponds to #1 in the pen, but I will rewrite the relevant code here. Border-color animates by splitting the colors to their red, green and blue components and raises/lowers them to it&#8217;s new value. ([Demo](http://codepen.io/brandonrozek/pen/PqzPMe){.broken_link}) ([Spec](http://www.w3.org/TR/css3-transitions/#animtype-color)) Example of animation corresponds to #1 in the pen, but I will rewrite the relevant code here.
```css ```css
@keyframes color { @keyframes color {
@ -102,7 +102,7 @@ For animation, this corresponds to #3 in the pen I made at the top. I&#8217;ll r
### Conclusion ### Conclusion
Animations are quite enjoyable. The last box in my Codepen demo tries combining all three of those animations. (Super Wacky!)  You don't need to use keyframe animations to achieve this, you can also use the transition property. I used keyframes so you can better visualize what's going on. There are plenty of other animatable properties to go through, so I'll get started on those. In the meantime, if you want to look at some of the sites I used for research I'll include the links below. Animations are quite enjoyable. The last box in my Codepen demo tries combining all three of those animations. (Super Wacky!)  You don&#8217;t need to use keyframe animations to achieve this, you can also use the transition property. I used keyframes so you can better visualize what&#8217;s going on. There are plenty of other animatable properties to go through, so I&#8217;ll get started on those. In the meantime, if you want to look at some of the sites I used for research I&#8217;ll include the links below.
- <https://developer.mozilla.org/en-US/docs/Web/CSS/animation> - <https://developer.mozilla.org/en-US/docs/Web/CSS/animation>
- <http://www.w3.org/TR/css3-transitions/#animatable-css> - <http://www.w3.org/TR/css3-transitions/#animatable-css>
- <https://developer.mozilla.org/en-US/docs/Web/CSS/border-color> - <https://developer.mozilla.org/en-US/docs/Web/CSS/border-color>

View file

@ -18,7 +18,7 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["Web", "CSS"] tags: ["Web", "CSS"]
--- ---
This post is part 2 of an animation series I am doing; you can read part 1 [here](https://brandonrozek.com/2015/05/animatable-border/). In this post, we'll look at the different parts of the box model (margin, padding, height, and width) and see how they can be animated. This post is part 2 of an animation series I am doing; you can read part 1 [here](https://brandonrozek.com/2015/05/animatable-border/). In this post, we&#8217;ll look at the different parts of the box model (margin, padding, height, and width) and see how they can be animated.
<!--more--> <!--more-->
@ -30,26 +30,37 @@ The W3C has a great starting reference for the [CSS Box Model](http://www.w3.org
* If you use 4 values, the first value is the top margin and the rest follow in a clockwise fashion * If you use 4 values, the first value is the top margin and the rest follow in a clockwise fashion
* Initial value: 0 * Initial value: 0
Margins can be described as the space around an element. In the Codepen demo (#1), it shows 2 boxes. The first box has a margin-right that is increasing, making it seem as though it's pushing the second box away. Margins can be described as the space around an element. In the Codepen demo (#1), it shows 2 boxes. The first box has a margin-right that is increasing, making it seem as though it&#8217;s pushing the second box away.
```css <pre><code class="language-css">
@keyframes margin { @keyframes margin {
to { margin-right: 7rem; }
to { margin-right: 7rem; }
} }
.margin { .margin {
display: inline-block;
height: 5rem; display: inline-block;
width: 5rem;
background-color: lightblue; height: 5rem;
vertical-align: top;
width: 5rem;
background-color: lightblue;
vertical-align: top;
} }
.margin:first-of-type { .margin:first-of-type {
margin-right: 0;
animation: margin 4s ease 0s infinite; margin-right: 0;
animation: margin 4s ease 0s infinite;
} }
``` </code></pre>
### Padding ### Padding
@ -59,7 +70,7 @@ Margins can be described as the space around an element. In the Codepen demo (#1
Padding is the space between the content and the border of an element. In the demo (#2),  it shows a box in which its padding is increasing. Padding is the space between the content and the border of an element. In the demo (#2),  it shows a box in which its padding is increasing.
```css <pre><code class="language-css">
@keyframes padding { @keyframes padding {
to { padding: 2rem; } to { padding: 2rem; }
@ -67,90 +78,113 @@ to { padding: 2rem; }
} }
.padding { .padding {
display: inline-block;
padding: 0;
background-color: lightgreen;
animation: padding 2.5s ease 0s infinite;
}
```
display: inline-block;
padding: 0;
background-color: lightgreen;
animation: padding 2.5s ease 0s infinite;
}
</code></pre>
### Height ### Height
* Accepts a non-negative number, this number is overridden however by (min/max)-height * Accepts a non-negative number, this number is overridden however by (min/max)-height
* Initial value: auto * Initial value: auto
&#8220;Height&#8221; is the height of an element without its padding, border, or margin. In the demo (#3) you can see the boxes' height shrink, and each box begins its animation at a different time. &#8220;Height&#8221; is the height of an element without its <span><span> padding, border, or margin. In the demo (#3) you can see the boxes&#8217; height shrink, and each box begins it&#8217;s animation at a different time. </span></span>
```css <pre><code class="language-css">
@keyframes height { @keyframes height {
to { height: .01rem; }
to { height: .01rem; }
} }
.height { .height {
display: inline-block;
height: 4rem; display: inline-block;
width: 3rem;
background-color: violet; height: 4rem;
animation: height 1.25s ease 0s infinite;
vertical-align: top; width: 3rem;
background-color: violet;
animation: height 1.25s ease 0s infinite;
vertical-align: top;
} }
.height:nth-of-type(n) { .height:nth-of-type(n) {
animation: height 1.25s ease .2s infinite alternate;
animation: height 1.25s ease .2s infinite alternate;
} }
.height:nth-of-type(2n) { .height:nth-of-type(2n) {
animation: height 1.25s ease .4s infinite alternate;
animation: height 1.25s ease .4s infinite alternate;
} }
.height:nth-of-type(3n) { .height:nth-of-type(3n) {
animation: height 1.25s ease .6s infinite alternate;
animation: height 1.25s ease .6s infinite alternate;
} }
``` </code></pre>
### Width ### Width
* Accepts a non-negative number, this number is overridden however by (min/max)-width * Accepts a non-negative number, this number is overridden however by (min/max)-width
* Initial value: auto * Initial value: auto
&#8220;Width&#8221; is the width of an element without its padding, border, or margin. In the demo (#4), it is similar to #3, however, its the width being affected as opposed to the height. &#8220;Width&#8221; is the width of an element without its <span><span> padding, border, or margin. In the demo (#4), it is similar to #3, however, it&#8217;s the width being affected as opposed to the height. </span></span>
```css <pre><code class="language-css">
@keyframes width { @keyframes width {
to { width: .01rem; }
to { width: .01rem; }
} }
.width { .width {
margin-bottom: .2rem;
height: 3rem; margin-bottom: .2rem;
width: 6.5rem;
background-color: bisque; height: 3rem;
width: 6.5rem;
background-color: bisque;
} }
.width:nth-of-type(n) { .width:nth-of-type(n) {
animation: width 1.25s ease .2s infinite alternate;
animation: width 1.25s ease .2s infinite alternate;
} }
.width:nth-of-type(2n) { .width:nth-of-type(2n) {
animation: width 1.25s ease .4s infinite alternate;
animation: width 1.25s ease .4s infinite alternate;
} }
.width:nth-of-type(3n) { .width:nth-of-type(3n) {
animation: width 1.25s ease .6s infinite alternate;
animation: width 1.25s ease .6s infinite alternate;
} }
```
</code></pre>
### Conclusion ### Conclusion
And so with this we can add another collection of animations to our toolbelt! If you're wondering why I left border out of this box-model post, its because I have already written a post dedicated to just the [border animation](https://brandonrozek.com/2015/05/animatable-border/). Here are some of the resources I looked at for this post. Hopefully I'll come back with another animatable post soon! And so with this we can add another collection of animations to our toolbelt! If you&#8217;re wondering why I left border out of this box-model post, it&#8217;s because I have already written a post dedicated to just the [border animation](https://brandonrozek.com/2015/05/animatable-border/). Here are some of the resources I looked at for this post. Hopefully I&#8217;ll come back with another animatable post soon! <https://developer.mozilla.org/en-US/docs/Web/CSS/margin> <https://docs.webplatform.org/wiki/css/properties/margin>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/padding> <https://docs.webplatform.org/wiki/css/properties/padding>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/height> <https://docs.webplatform.org/wiki/css/properties/height>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/width> <https://docs.webplatform.org/wiki/css/properties/width>{.broken_link}
- https://developer.mozilla.org/en-US/docs/Web/CSS/margin
- https://web.archive.org/web/20151112043907/https://docs.webplatform.org/wiki/css/properties/margin
- https://developer.mozilla.org/en-US/docs/Web/CSS/padding
- https://docs.webplatform.org/wiki/css/properties/padding
- https://developer.mozilla.org/en-US/docs/Web/CSS/height
- https://docs.webplatform.org/wiki/css/properties/height
- https://developer.mozilla.org/en-US/docs/Web/CSS/width
- https://web.archive.org/web/20150919163210/https://docs.webplatform.org/wiki/css/properties/width

View file

@ -19,7 +19,7 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["Web", "CSS"] tags: ["Web", "CSS"]
--- ---
Animating the location of objects is one of the most common types of animation. It's interesting to animate this way because you need to keep in mind how each of the elements interact with each other to constitute a page. Animating the location of objects is one of the most common types of animation. It&#8217;s interesting to animate this way because you need to keep in mind how each of the element&#8217;s interact with each other to constitute a page.
<!--more--> <!--more-->
@ -29,7 +29,7 @@ This is part 4 of my series on animation. Check out the other parts of this seri
* Part 2 — [Animatable: Box Model](https://brandonrozek.com/2015/09/animatable-box-model/) * Part 2 — [Animatable: Box Model](https://brandonrozek.com/2015/09/animatable-box-model/)
* Part 3 — [Animatable: Text](https://brandonrozek.com/2015/10/animatable-text/) * Part 3 — [Animatable: Text](https://brandonrozek.com/2015/10/animatable-text/)
This post goes along well with this [Codepen demo](http://codepen.io/brandonrozek/full/NGbWzo/){.broken_link}, I'll reference it multiple times in this post. Now onto animations! This post goes along well with this [Codepen demo](http://codepen.io/brandonrozek/full/NGbWzo/){.broken_link}, I&#8217;ll reference it multiple times in this post. Now onto animations!
### background-position ### background-position
@ -37,60 +37,87 @@ This post goes along well with this [Codepen demo](http://codepen.io/brandonroze
* Offset-x | Offset-Y * Offset-x | Offset-Y
* Initial Value: 0% 0% * Initial Value: 0% 0%
Background-position sets where the background is relative to its background-origin. In the Codepen demo (#1), you can see the background image scrolling horizontally. Background-position sets where the background is relative to it&#8217;s background-origin. In the Codepen demo (#1), you can see the background image scrolling horizontally.
```css <pre><code class="language-css">
@keyframes background-position { @keyframes background-position {
to { background-position: 100% 0%; } to { background-position: 100% 0%; }
} }
.background-position { .background-position {
background-image: url(https://upload.wikimedia.org/wikipedia/commons/d/d3/Tajik_mountains_edit.jpg); background-image: url(https://upload.wikimedia.org/wikipedia/commons/d/d3/Tajik_mountains_edit.jpg);
height: 6rem; height: 6rem;
width: 8rem; width: 8rem;
background-size: 200% 100%; background-size: 200% 100%;
background-position: 0% 0%; background-position: 0% 0%;
animation: background-position 5s linear .1s infinite alternate; animation: background-position 5s linear .1s infinite alternate;
} }
``` </code></pre>
### position with left, right, top, bottom ### position with left, right, top, bottom
* Accepts length, percentage, or some keywords * Accepts length, percentage, or some keywords
* Initial value: auto * Initial value: auto
The left, right, top, and bottom properties require the position to be set to something other than static. When you add a value to any of these properties just imagine that value pushing the element on that side. For example: for `left: 2rem` imagine that the element is being pushed on the left side by 2rem, making it move to the right 2rem. In the demo (#2), the box is being pushed in a square path. The left, right, top, and bottom properties require the position to be set to something other than static. When you add a value to any of these properties just imagine that value pushing the element on that side. For example: for &#8220;left: 2rem&#8221; imagine that the element is being pushed on the left side by 2rem, making it move to the right 2rem. In the demo (#2), the box is being pushed in a square path.
```css <pre><code class="language-css">
@keyframes position { @keyframes position {
25% { 25% {
top: 0; top: 0;
left: 3rem; left: 3rem;
} }
50% { 50% {
top: 3rem; top: 3rem;
left: 3rem; left: 3rem;
} }
75% { 75% {
top: 3rem; top: 3rem;
left: 0; left: 0;
} }
} }
.position { .position {
position: relative; position: relative;
top: 0; top: 0;
left: 0; left: 0;
height: 3rem; height: 3rem;
width: 3rem; width: 3rem;
background-color: lightblue; background-color: lightblue;
animation: position 1.5s ease .1s infinite; animation: position 1.5s ease .1s infinite;
} }
``` </code></pre>
 
### vertical-align ### vertical-align
@ -99,18 +126,23 @@ The left, right, top, and bottom properties require the position to be set to so
Vertical-align sets how vertically the inline element or text is compared to the baseline. In the Codepen demo (#3), the question has its vertical align being manipulated which causes the &#8220;Maybe&#8221; to bounce up and down. Vertical-align sets how vertically the inline element or text is compared to the baseline. In the Codepen demo (#3), the question has its vertical align being manipulated which causes the &#8220;Maybe&#8221; to bounce up and down.
```css <pre><code class="language-css">
@keyframes vertical-align { @keyframes vertical-align {
to { vertical-align: 1rem; } to { vertical-align: 1rem; }
} }
.vertical-align { .vertical-align {
font-size: 1.5rem;
vertical-align: 0;
animation: vertical-align 1s ease-out .1s infinite alternate;
}
```
font-size: 1.5rem;
vertical-align: 0;
animation: vertical-align 1s ease-out .1s infinite alternate;
}
</code></pre>
### z-index ### z-index
@ -119,58 +151,78 @@ Vertical-align sets how vertically the inline element or text is compared to the
If elements overlap, z-index determines which element appears on top. If the z-index is the same, then it is controlled by source order. In the demo (#4), The z-index of the biggest box changes, revealing what is under it. If elements overlap, z-index determines which element appears on top. If the z-index is the same, then it is controlled by source order. In the demo (#4), The z-index of the biggest box changes, revealing what is under it.
```css <pre><code class="language-css">
@keyframes z-index { @keyframes z-index {
to { z-index: 0; } to { z-index: 0; }
} }
.z-index { .z-index {
position: absolute; position: absolute;
left: 1rem; left: 1rem;
display: inline-block; display: inline-block;
} }
.z-index:nth-child(1) { .z-index:nth-child(1) {
height: 1rem; height: 1rem;
width: 1rem; width: 1rem;
background-color: lightgreen; background-color: lightgreen;
z-index: 4; z-index: 4;
} }
.z-index:nth-child(2) { .z-index:nth-child(2) {
height: 2rem; height: 2rem;
width: 2rem; width: 2rem;
background-color: #F4FFA4; background-color: #F4FFA4;
z-index: 3; z-index: 3;
} }
.z-index:nth-child(3) { .z-index:nth-child(3) {
height: 3rem; height: 3rem;
width: 3rem; width: 3rem;
background-color: #DEB0ED; background-color: #DEB0ED;
z-index: 2; z-index: 2;
} }
.z-index:nth-child(4) { .z-index:nth-child(4) {
height: 4rem; height: 4rem;
width: 4rem; width: 4rem;
background-color: #D8EADF; background-color: #D8EADF;
z-index: 5; z-index: 5;
animation: z-index 1s ease .1s infinite alternate; animation: z-index 1s ease .1s infinite alternate;
} }
``` </code></pre>
### Conclusion ### Conclusion
By animating the location of an element, it opens up a whole bunch of different opportunities. Using motion, you can signify that the user has indeed pressed the button, instead of what would otherwise leave them there clicking on the button multiple times thinking that nothing has happened. Using motion, you can bring a webpage that would've otherwise been boring to life. Use these animations to work, and I'll be back with another animatable post soon! By animating the location of an element, it opens up a whole bunch of different opportunities. Using motion, you can signify that the user has indeed pressed the button, instead of what would otherwise leave them there clicking on the button multiple times thinking that nothing has happened. Using motion, you can bring a webpage that would&#8217;ve otherwise been boring to life. Use these animations to work, and I&#8217;ll be back with another animatable post soon!
#### The links #### The links
- https://developer.mozilla.org/en-US/docs/Web/CSS/background-position <https://developer.mozilla.org/en-US/docs/Web/CSS/background-position> <https://developer.mozilla.org/en-US/docs/Web/CSS/left> <https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align> <https://developer.mozilla.org/en-US/docs/Web/CSS/z-index> <https://docs.webplatform.org/wiki/css/properties/background-position>{.broken_link} <https://docs.webplatform.org/wiki/css/properties/left>{.broken_link} <https://docs.webplatform.org/wiki/css/properties/vertical-align>{.broken_link} <https://docs.webplatform.org/wiki/css/properties/z-index>{.broken_link}
- https://developer.mozilla.org/en-US/docs/Web/CSS/left
- https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
- https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
- https://docs.webplatform.org/wiki/css/properties/background-position
- https://docs.webplatform.org/wiki/css/properties/left
- https://docs.webplatform.org/wiki/css/properties/vertical-align
- https://docs.webplatform.org/wiki/css/properties/z-index

View file

@ -17,7 +17,7 @@ kind:
- article - article
tags: ["Web", "CSS"] tags: ["Web", "CSS"]
--- ---
This post is part 3 of my series on animation. In this post, I'll show you different animations you can add onto text. If you haven't already, you should check out [part 1](https://brandonrozek.com/2015/09/animatable-box-model/) and [part 2](https://brandonrozek.com/2015/05/animatable-border/) of this series. Animations on text can be used to bring attention, to add importance, or to convey a point. As with all animations, however, keep your user in mind and your text readable. This post is part 3 of my series on animation. In this post, I&#8217;ll show you different animations you can add onto text. If you haven&#8217;t already, you should check out [part 1](https://brandonrozek.com/2015/09/animatable-box-model/) and [part 2](https://brandonrozek.com/2015/05/animatable-border/) of this series. Animations on text can be used to bring attention, to add importance, or to convey a point. As with all animations, however, keep your user in mind and your text readable.
<!--more--> <!--more-->
@ -28,59 +28,77 @@ This post follows along with a [Codepen demo](http://codepen.io/brandonrozek/ful
* Accepts certain keywords, or any positive number or length * Accepts certain keywords, or any positive number or length
* Initial value: normal * Initial value: normal
Line-height is the space between each line in a text block. It is commonly recommended that you use a unitless line-height because then it takes the font-size into consideration. When you use an unitless value, the browser determines the line-height by taking the unitless value and multiplying it by the element's font-size. In the Codepen demo (#1), you can see the line-height decreasing while the opacity increases. Line-height is the space between each line in a text block. It is commonly recommended that you use a unitless line-height because then it takes the font-size into consideration. When you use an unitless value, the browser determines the line-height by taking the unitless value and multiplying it by the element&#8217;s font-size. In the Codepen demo (#1), you can see the line-height decreasing while the opacity increases.
```css <pre><code class="language-css">
@keyframes line-height { @keyframes line-height {
to { to {
opacity: 1; opacity: 1;
line-height: 1.2; line-height: 1.2;
} }
} }
.line-height { .line-height {
opacity: 0;
line-height: 2.5;
animation: line-height .75s ease .2s infinite;
}
```
opacity: 0;
line-height: 2.5;
animation: line-height .75s ease .2s infinite;
}
</code></pre>
### font-weight ### font-weight
* Accepts certain keywords or 100, 200, 300, 400, 500, 600, 700, 800, 900 (the higher the number, the darker the font-weight) * Accepts certain keywords or 100, 200, 300, 400, 500, 600, 700, 800, 900 (the higher the number, the darker the font-weight)
* Initial value: normal * Initial value: normal
Font-weight specifies the boldness of the text. If the typeface doesn't come with multiple weights, then the animation would only happen between the weights that it does have. In the demo (#2), the text will go from normal weight to bold. Font-weight specifies the boldness of the text. If the typeface doesn&#8217;t come with multiple weights, then the animation would only happen between the weights that it does have. In the demo (#2), the text will go from normal weight to bold.
```css <pre><code class="language-css">
@keyframes font-weight { @keyframes font-weight {
to { font-weight: 900;} to { font-weight: 900;}
} }
.font-weight { .font-weight {
font-weight: 100; font-weight: 100;
animation: font-weight 2s linear .2s infinite alternate; animation: font-weight 2s linear .2s infinite alternate;
} }
``` </code></pre>
### font-size ### font-size
* Accepts any length * Accepts any length
* Initial value: medium * Initial value: medium
It is important to note that changing the font-size could change the value of other text properties that are dependent upon it. (Like unitless line-heights) In the demo (#3), you can see the text's font-size shrinking. It is important to note that changing the font-size could change the value of other text properties that are dependent upon it. (Like unitless line-heights) In the demo (#3), you can see the text&#8217;s font-size shrinking.
```css <pre><code class="language-css">
@keyframes font-size { @keyframes font-size {
to { font-size: .1rem;} to { font-size: .1rem;}
} }
.font-size { .font-size {
font-size: 2rem; font-size: 2rem;
animation: font-size 2s ease-out .1s infinite; animation: font-size 2s ease-out .1s infinite;
} }
``` </code></pre>
### text-shadow ### text-shadow
@ -88,19 +106,25 @@ It is important to note that changing the font-size could change the value of ot
* Color | Offset-X | Offset-Y | Blur-radius * Color | Offset-X | Offset-Y | Blur-radius
* Initial value: none * Initial value: none
Text-shadow applies a shadow to both the text and its text-decoration. Multiple shadows can be added, and they are applied from front to back. In the animation (#4), you can see the text's shadow move. Text-shadow applies a shadow to both the text and it&#8217;s text-decoration. Multiple shadows can be added, and they are applied from front to back. In the animation (#4), you can see the text&#8217;s shadow move.
```css <pre><code class="language-css">
@keyframes text-shadow { @keyframes text-shadow {
to { text-shadow: 25px 10px 5px rgba(0, 0, 0, .9);} to { text-shadow: 25px 10px 5px rgba(0, 0, 0, .9);}
} }
.text-shadow { .text-shadow {
font-size: 1.5rem; font-size: 1.5rem;
text-shadow: -10px 5px 3.5px rgba(0, 0, 0, .3); text-shadow: -10px 5px 3.5px rgba(0, 0, 0, .3);
animation: text-shadow 1s ease 0s infinite; animation: text-shadow 1s ease 0s infinite;
} }
``` </code></pre>
### text-decoration-color ### text-decoration-color
@ -109,18 +133,23 @@ Text-shadow applies a shadow to both the text and its text-decoration. Multiple
This sets the color for [text-decoration-line](https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-line) (underlines, overlines, or strike-throughs) In the demo (#5), the strike-through changes from red to black. This sets the color for [text-decoration-line](https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-line) (underlines, overlines, or strike-throughs) In the demo (#5), the strike-through changes from red to black.
```css <pre><code class="language-css">
@keyframes text-decoration-color { @keyframes text-decoration-color {
to { text-decoration-color: black;} to { text-decoration-color: black;}
} }
.text-decoration-color { .text-decoration-color {
text-decoration-color: red;
text-decoration-line: line-through;
animation: text-decoration-color 2s linear 0s infinite alternate;
}
```
text-decoration-color: red;
text-decoration-line: line-through;
animation: text-decoration-color 2s linear 0s infinite alternate;
}
</code></pre>
### word-spacing ### word-spacing
@ -129,17 +158,21 @@ This sets the color for [text-decoration-line](https://developer.mozilla.org/en-
Word-spacing defines the space between tags and words. Negative values bring the words closer to each other. In the demo (#6), you can see the word-spacing increase with &#8216;good bye!&#8217; where the word &#8216;bye!&#8217; is moving away. Word-spacing defines the space between tags and words. Negative values bring the words closer to each other. In the demo (#6), you can see the word-spacing increase with &#8216;good bye!&#8217; where the word &#8216;bye!&#8217; is moving away.
```css <pre><code class="language-css">
@keyframes word-spacing { @keyframes word-spacing {
to { word-spacing: 5rem;} to { word-spacing: 5rem;}
} }
.word-spacing { .word-spacing {
word-spacing: normal;
animation: word-spacing 1s ease-in 0s infinite;
}
```
word-spacing: normal;
animation: word-spacing 1s ease-in 0s infinite;
}
</code></pre>
### letter-spacing ### letter-spacing
@ -148,35 +181,26 @@ Word-spacing defines the space between tags and words. Negative values bring the
Letter-spacing specifies the spacing between text characters. Negative values bring the letters closer together. In the demo (#7), each letter gets separated from one another. Letter-spacing specifies the spacing between text characters. Negative values bring the letters closer together. In the demo (#7), each letter gets separated from one another.
```css <pre><code class="language-css">
@keyframes letter-spacing { @keyframes letter-spacing {
to { letter-spacing: 2rem;} to { letter-spacing: 2rem;}
} }
.letter-spacing { .letter-spacing {
letter-spacing: 0;
animation: letter-spacing .75s ease 0s infinite alternate;
}
```
letter-spacing: 0;
animation: letter-spacing .75s ease 0s infinite alternate;
}
</code></pre>
### Conclusion ### Conclusion
These animations show the different things you can do with text. Perhaps you'll add a small animation to a heading to bring depth and attention, or you'll add some to the text of a button to scream &#8220;call to action&#8221;. Whatever you decide, I hope this post helped. I'll see you again next time with another animatable post! 🙂 These animations show the different things you can do with text. Perhaps you&#8217;ll add a small animation to a heading to bring depth and attention, or you&#8217;ll add some to the text of a button to scream &#8220;call to action&#8221;. Whatever you decide, I hope this post helped. I&#8217;ll see you again next time with another animatable post! 🙂
#### The links #### The links
- [https://docs.webplatform.org/wiki/css/properties/line-height](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height) [https://docs.webplatform.org/wiki/css/properties/line-height](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height) <https://developer.mozilla.org/en-US/docs/Web/CSS/line-height> <https://docs.webplatform.org/wiki/css/properties/font-weight>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight> <https://docs.webplatform.org/wiki/css/properties/font-size>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/font-size> <https://docs.webplatform.org/wiki/css/properties/text-shadow>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow> <https://docs.webplatform.org/wiki/css/properties/text-decoration-color>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-color> <https://docs.webplatform.org/wiki/css/properties/word-spacing>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/word-spacing> <https://docs.webplatform.org/wiki/css/properties/letter-spacing>{.broken_link} <https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing>
- https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
- https://docs.webplatform.org/wiki/css/properties/font-weight
- https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
- https://docs.webplatform.org/wiki/css/properties/font-size
- https://developer.mozilla.org/en-US/docs/Web/CSS/font-size
- https://docs.webplatform.org/wiki/css/properties/text-shadow
- https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow
- https://docs.webplatform.org/wiki/css/properties/text-decoration-color
- https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-color
- https://docs.webplatform.org/wiki/css/properties/word-spacing
- https://developer.mozilla.org/en-US/docs/Web/CSS/word-spacing
- https://docs.webplatform.org/wiki/css/properties/letter-spacing
- https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing

View file

@ -18,7 +18,7 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["Web"] tags: ["Web"]
--- ---
I've been teaching a small class on web development recently, and after my first lecture, I've gained a newfound respect for teachers. Teaching didn't come as naturally to me as I would have imagined. I tried going in prepared: with a few outlines and a few code demos. Instead of letting my preparation go to waste, I decided to share them here with you on my site. It's a nice break from the Animatable posts, so I hope you enjoy! I&#8217;ve been teaching a small class on web development recently, and after my first lecture, I&#8217;ve gained a newfound respect for teachers. Teaching didn&#8217;t come as naturally to me as I would have imagined. I tried going in prepared: with a few outlines and a few code demos. Instead of letting my preparation go to waste, I decided to share them here with you on my site. It&#8217;s a nice break from the Animatable posts, so I hope you enjoy!
<!--more--> <!--more-->
@ -27,15 +27,15 @@ I suggest a couple short readings to check out before the lecture:
* [What is CSS](http://www.sitepoint.com/web-foundations/css/) by Adam Roberts * [What is CSS](http://www.sitepoint.com/web-foundations/css/) by Adam Roberts
* [Box Model](http://www.w3.org/TR/CSS2/box.html) by the W3C * [Box Model](http://www.w3.org/TR/CSS2/box.html) by the W3C
Take a quick look if you wish. These are mostly to give an idea of what is going to happen over the next few lectures. What is HTML, CSS, and Javascript? We'll look into the different parts that form a webpage and how they all interact with each other. Take a quick look if you wish. These are mostly to give an idea of what is going to happen over the next few lectures. What is HTML, CSS, and Javascript? We&#8217;ll look into the different parts that form a webpage and how they all interact with each other.
## HTML ## HTML
HTML is where the content of your site lives. It's also the file the server returns to no matter what, the bare-bones of a webpage. This file may contain text, pictures, and/or other media. HTML is where the content of your site lives. It&#8217;s also the file the server returns to no matter what, the bare-bones of a webpage. This file may contain text, pictures, and/or other media.
## CSS ## CSS
This is where you style your content. Whether it's through colors, layout, or typography, there are plenty of different ways for you to visually manipulate your content. This is where you style your content. Whether it&#8217;s through colors, layout, or typography, there are plenty of different ways for you to visually manipulate your content.
## Javascript ## Javascript
@ -49,79 +49,77 @@ HTML, CSS, and Javascript each do what they do the best. So how can you have the
Link the CSS file Link the CSS file
```html <pre><code class="language-markup">
<link rel='stylesheet' href='style.css'> &lt;link rel='stylesheet' href='style.css' /&gt;
``` </code></pre>
Link the Javascript file Link the Javascript file
```html <pre><code class="language-markup">
<script src='script.js'></script> &lt;script src='script.js'&gt;&lt;/script&gt;
``` </code></pre>
Give the `<p>` tag a class of hello and id of world to use in CSS and Javascript Give the <p> tag a class of hello and id of world to use in CSS and Javascript
```html <pre><code class="language-markup">
<p class='hello' id='world'></p> &lt;p class='hello' id='world'&gt;&lt;/p&gt;
``` </code></pre>
### In CSS ### In CSS
Refer to any element with `class='hello'` and change it's text color to red. Refer to any element with class=&#8217;hello&#8217; and change it&#8217;s text color to red.
```css <pre><code class="language-css">
.hello { color: red; } .hello { color: red; }
``` </code></pre>
Any element with an `id='world'` will have it's font-size changed to 2rem Any element with an id=&#8217;world&#8217; will have it&#8217;s font-size changed to 2rem
```css <pre><code class="language-css">
#world { font-size: 2rem; } #world { font-size: 2rem; }
``` </code></pre>
You don&#8217;t have to only use the class and id attributes in html, you can refer to any attribute. This code snippet grabs any canvas element with data=&#8217;sales&#8217; and changes it&#8217;s border to be 5px thick, dashed, and the color blue.
You don't have to only use the class and id attributes in html, you can refer to any attribute. This code snippet grabs any canvas element with `data='sales'` and changes it's border to be 5px thick, dashed, and the color blue. <pre><code class="language-css">
```css
canvas[data=sales] { border: 5px dashed blue; } canvas[data=sales] { border: 5px dashed blue; }
``` </code></pre>
### In Javascript ### In Javascript
Javascript has many properties and methods you can use to reference different HTML elements To grab (an) element(s) Javascript has many properties and methods you can use to reference different HTML elements To grab (an) element(s)
```js <pre><code class="language-javascript">
document.getElementById(); document.getElementById();
document.getElementsByClassName(); //Returns an array of element(s) document.getElementsByClassName(); //Returns an array of element(s)
document.querySelector(); //Returns the first matching selector document.querySelector(); //Returns the first matching selector
document.querySelectorAll(); //Returns an array of element(s) document.querySelectorAll(); //Returns an array of element(s)
``` </code></pre>
To add a class to an element To add a class to an element
```js <pre><code class="language-javascript">
element.className += “ random-class” //Note the space element.className += “ random-class” //Note the space
</code></pre>
```
To check whether a certain condition is true in the browser To check whether a certain condition is true in the browser
```js <pre><code class="language-javascript">
window.matchMedia('aspect-ratio: 12/8'); //Returns true if the aspect ratio is 12/8 window.matchMedia('aspect-ratio: 12/8'); //Returns true if the aspect ratio is 12/8
window.innerHeight; //Is the height of the window window.innerHeight; //Is the height of the window
window.innerWidth; //Is the width of the window window.innerWidth; //Is the width of the window
``` </code></pre>
_And a lot more_ _And a lot more_
## What should handle what? ## What should handle what?
HTML, CSS, and Javascript should all handle what each of them does best. HTML should handle the content, CSS should handle the styles/presentation, and Javascript should handle the behavior of the webpage. Why, you ask? One reason is that it demonstrates a &#8220;separation of concerns&#8221;. It would be a mess if you're writing an article in the HTML and you put style attributes all over the place. That would make the markup confusing and hard to read/edit. HTML, CSS, and Javascript should all handle what each of them does best. HTML should handle the content, CSS should handle the styles/presentation, and Javascript should handle the behavior of the webpage. Why, you ask? One reason is that it demonstrates a &#8220;separation of concerns&#8221;. It would be a mess if you&#8217;re writing an article in the HTML and you put style attributes all over the place. That would make the markup confusing and hard to read/edit.
## Can't I just put everything in a Javascript file? ## Can&#8217;t I just put everything in a Javascript file?
Yes you can, but then you lose some of the great features of HTML and CSS. HTML and CSS ignore everything that it doesn't understand. When Javascript encounters something it doesn't understand, it stops running the code completely, regardless of what comes after. Please note that I am only speaking about what gets served to the user. When it comes to what's actually on your server, then store your content however you wish. Yes you can, but then you lose some of the great features of HTML and CSS. HTML and CSS ignore everything that it doesn&#8217;t understand. When Javascript encounters something it doesn&#8217;t understand, it stops running the code completely, regardless of what comes after. Please note that I am only speaking about what gets served to the user. When it comes to what&#8217;s actually on your server, then store your content however you wish.
## Conclusion ## Conclusion
To me personally, my first lecture was a mess. Some of my examples didn't work properly in the first type-through and I was everywhere. Though, to be sharing the little knowledge I do have, comes with its own joy. It must not have gone as terrible as I imagined it in my head because they seemed enthusiastic for the next lecture. So I'm excited to share this outline with you, and hopefully I'll have many more to come. Until next time. 🙂 To me personally, my first lecture was a mess. Some of my examples didn&#8217;t work properly in the first type-through and I was everywhere. Though, to be sharing the little knowledge I do have, comes with it&#8217;s own joy. It must not have gone as terrible as I imagined it in my head because they seemed enthusiastic for the next lecture. So I&#8217;m excited to share this outline with you, and hopefully I&#8217;ll have many more to come. Until next time. 🙂

View file

@ -20,266 +20,288 @@ tags: ["Web", "JS"]
--- ---
Javascript has multiple ways you can store your data. Each of these different ways is called a data type, and they each carry different “methods” which are helpful commands. Today, Ill show you the different data types and methods that I use and how theyre useful. Javascript has multiple ways you can store your data. Each of these different ways is called a data type, and they each carry different “methods” which are helpful commands. Today, Ill show you the different data types and methods that I use and how theyre useful.
<!--more-->
This post is by far not a comprehenive list of all the Data types and their methods. If you want one of those, please check out [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) and/or [WebPlatform](http://docs.webplatform.org/wiki/javascript/objects){.broken_link}. This is the second lecture of the web development class Im teaching for the newer folks over at [Math I/O](http://math-io.com). Due to the nature of Math I/O (making math games and all), the next few posts will be Javascript centric. Were getting ready to build a new game, so I want to prepare them as much as possible. \*Excited\* ^_^ Ilya Kantor does a good job of descibing Javascript data types and their many methods in [Mastering Data Types](http://javascript.info/tutorial/mastering-data-types) which I made the recommended reading for this lecture. This post is by far not a comprehenive list of all the Data types and their methods. If you want one of those, please check out [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) and/or [WebPlatform](http://docs.webplatform.org/wiki/javascript/objects){.broken_link}. This is the second lecture of the web development class Im teaching for the newer folks over at [Math I/O](http://math-io.com). Due to the nature of Math I/O (making math games and all), the next few posts will be Javascript centric. Were getting ready to build a new game, so I want to prepare them as much as possible. \*Excited\* ^_^ Ilya Kantor does a good job of descibing Javascript data types and their many methods in [Mastering Data Types](http://javascript.info/tutorial/mastering-data-types) which I made the recommended reading for this lecture.
### String ### <a href="#string" name="string"></a>String {#string}
A string is one or more characters. A string is one or more characters.
```javascript <pre><code class="language-javascript">var name = "Brandon";</code></pre>
var name = "Brandon";
```
You can access a character inside of a string by using [] notation. Inside the [] you put the index of the character you want. An index is the numeral location of the character starting from the left. It is important to note that Javascript starts counting from 0. You can access a character inside of a string by using [] notation. Inside the [] you put the index of the character you want. An index is the numeral location of the character starting from the left. It is important to note that Javascript starts counting from 0.
| B | r | a | n | d | o | n | <table border="1">
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | <tr>
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | <td>
B
</td>
<td>
r
</td>
```javascript <td>
var firstInitial = "Brandon"[0]; a
``` </td>
Now the value of firstInitial is the letter `"B"`.
#### Some useful methods for strings <td>
n
</td>
##### `String.prototype.indexOf` <td>
d
</td>
<td>
o
</td>
<td>
n
</td>
</tr>
<tr>
<td>
</td>
<td>
1
</td>
<td>
2
</td>
<td>
3
</td>
<td>
4
</td>
<td>
5
</td>
<td>
6
</td>
</tr>
</table>
<pre><code class="language-javascript">var firstInitial = "Brandon"[0];</code></pre>
Now the value of firstInitial is the letter <code class="language-javascript">"B"</code>.
#### <a href="#some-useful-methods-for-strings" name="some-useful-methods-for-strings"></a>Some useful methods for strings {#some-useful-methods-for-strings}
##### <a href="#string.prototype.indexof();" name="string.prototype.indexof();"></a>String.prototype.indexOf(); {#string.prototype.indexof();}
This can be used to find the index of any character(s) in a string. I primarily use it for when I need to check if something exists in a string. Do I have a z in my name? This can be used to find the index of any character(s) in a string. I primarily use it for when I need to check if something exists in a string. Do I have a z in my name?
```javascript <pre><code class="language-javascript">"Brandon".indexOf('z');</code></pre>
"Brandon".indexOf('z');
```
Nope, so Javascript will return a `-1`. How about a d? Nope, so Javascript will return a <code class="language-javascript">-1</code>. How about a d?
```javascript <pre><code class="language-javascript">"Brandon".indexOf('d');</code></pre>
"Brandon".indexOf('d');
```
Yes, Javascript will return `5` which is the index of the letter `d`. Yes, Javascript will return <code class="language-javascript">5</code> which is the index of the letter d.
##### `String.prototype.replace` ##### <a href="#string.prototype.replace();" name="string.prototype.replace();"></a>String.prototype.replace(); {#string.prototype.replace();}
The replace method can replace any character(s) with other character(s). For more complex replacing, look into [Regular Expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) and how you can use them in `.replace()`. Replace the first `n` in my name with an `m`. The replace method can replace any character(s) with other character(s). For more complex replacing, look into [Regular Expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) and how you can use them in .replace(). Replace the first n in my name with an m.
```javascript <pre><code class="language-javascript">
var modifiedName = "Brandon".replace('n', 'm'); var modifiedName = "Brandon".replace('n', 'm');
console.log(modifiedName); console.log(modifiedName);
``` </code></pre>
Logs `"Bramdon"`. Logs <code class="language-javascript">"Bramdon"</code>.
##### `String.prototype.toUpperCase` ##### <a href="#string.prototype.touppercase();" name="string.prototype.touppercase();"></a>String.prototype.toUpperCase(); {#string.prototype.touppercase();}
This method returns the string with all the lowercase characters converted to uppercase and can be useful for when youre checking user input and you dont want to worry about different cases. This method returns the string with all the lowercase characters converted to uppercase and can be useful for when youre checking user input and you dont want to worry about different cases.
```javascript <pre><code class="language-javascript">"Brandon".toUpperCase();</code></pre>
"Brandon".toUpperCase();
```
Returns `"BRANDON"`. Returns <code class="language-javascript">"BRANDON"</code>.
##### `String.prototype.toLowerCase()` ##### <a href="#string.prototype.tolowercase();" name="string.prototype.tolowercase();"></a>String.prototype.toLowerCase(); {#string.prototype.tolowercase();}
Same as above but instead of converting lowercase to uppercase, it converts uppercase to lowercase. Same as above but instead of converting lowercase to uppercase, it converts uppercase to lowercase.
```javascript <pre><code class="language-javascript">"Brandon".toLowerCase();</code></pre>
"Brandon".toLowerCase();
```
Returns `"brandon"`. Returns <code class="language-javascript">"brandon"</code>.
#### A couple useful escape secquences #### <a href="#a-couple-useful-escape-secquences" name="a-couple-useful-escape-secquences"></a>A couple useful escape secquences {#a-couple-useful-escape-secquences}
* `\n` for newline. * <code class="language-javascript">n</code> for newline.
* `\t` for tab character. * <code class="language-javascript">t</code> for tab character.
You can also use escape sequnces if you want to add `“”` or `` to your strings. You can also use escape sequnces if you want to add “” or to your strings.
<pre><code class="language-javascript">
var greeting = "Hello "Brandon"";
```javascript
var greeting = "Hello \"Brandon\"";
console.log(greeting); console.log(greeting);
``` </code></pre>
Returns `"Hello "Brandon""`. Returns <code class="language-javascript">"Hello "Brandon""</code>.
### Number ### <a href="#number" name="number"></a>Number {#number}
Any number between -(2^53 1) and (2^53 1). Any number between -(2<sup>53</sup> 1) and (2<sup>53</sup> 1).
#### Number Methods #### <a href="#number-methods" name="number-methods"></a>Number Methods {#number-methods}
Number methods are useful when trying to represent complex numbers. Number methods are useful when trying to represent complex numbers.
##### `Number.prototype.toExponential()` ##### <a href="#number.prototype.toexponential();" name="number.prototype.toexponential();"></a>Number.prototype.toExponential(); {#number.prototype.toexponential();}
Returns a string representing a number in exponential notation. Returns a string representing a number in exponential notation.
```javascript <pre><code class="language-javascript">77.1234.toExponential(2);</code></pre>
77.1234.toExponential(2);
```
Returns `"7.71e+1"`. Returns <code class="language-javascript">"7.71e+1"</code>.
##### `Number.prototype.toFixed()` ##### <a href="#number.prototype.tofixed();" name="number.prototype.tofixed();"></a>Number.prototype.toFixed(); {#number.prototype.tofixed();}
Returns a string representing a number fixed to x amount of decimal places. Returns a string representing a number fixed to x amount of decimal places.
```javascript <pre><code class="language-javascript">12345.6789.toFixed(1);</code></pre>
12345.6789.toFixed(1);
```
Returns `"12345.7"`. Returns <code class="language-javascript">"12345.7"</code>.
##### `Number.prototype.toPrecision();` ##### <a href="#number.prototype.toprecision();" name="number.prototype.toprecision();"></a>Number.prototype.toPrecision(); {#number.prototype.toprecision();}
Returns a string representing a number using x amount of significant figures. Returns a string representing a number using x amount of significant figures.
```javascript <pre><code class="language-javascript">5.123456.toPrecision(2);</code></pre>
5.123456.toPrecision(2);
```
Returns `"5.1"`. Returns <code class="language-javascript">"5.1"</code>.
#### Math properties/methods #### <a href="#math-properties/methods" name="math-properties/methods"></a>Math properties/methods {#math-properties/methods}
In Javascript there is a Math object which contains many properties and methods which are useful for mathmatical calculations. In Javascript there is a Math object which contains many properties and methods which are useful for mathmatical calculations.
##### Return Eulers constant ##### <a href="#return-euler's-constant" name="return-euler's-constant"></a>Return Eulers constant {#return-euler's-constant}
`Math.E` which returns ~2.718. <code class="language-javascript">Math.E</code> which returns ~2.718.
##### Return the natural log of x ##### <a href="#return-the-natural-log-of-x" name="return-the-natural-log-of-x"></a>Return the natural log of x {#return-the-natural-log-of-x}
```javascript <code class="language-javascript">Math.log(x)</code>
Math.log(x)
```
##### Rise x to the y power ##### <a href="#rise-x-to-the-y-power" name="rise-x-to-the-y-power"></a>Rise x to the y power {#rise-x-to-the-y-power}
```javascript <code class="language-javascript">Math.pow(x,y)</code>
Math.pow(x,y)
```
##### Return a psuedo random number \[0,1\) ##### <a href="#return-a-psuedo-random-number-[0,1)" name="return-a-psuedo-random-number-[0,1)"></a>Return a psuedo random number [0,1) {#return-a-psuedo-random-number-[0,1)}
```javascript <code class="language-javascript">Math.random()</code>
Math.random()
```
##### Round x to the nearest integer ##### <a href="#round-x-to-the-nearest-integer" name="round-x-to-the-nearest-integer"></a>Round x to the nearest integer {#round-x-to-the-nearest-integer}
```javascript <code class="language-javascript">Math.round(x)</code>
Math.round(x)
```
### Boolean ### <a href="#boolean" name="boolean"></a>Boolean {#boolean}
Booleans are either `true` or `false` and are typically used in conditional statements. You can either create them explicitly Booleans are either <code class="language-javascript">true</code> or <code class="language-javascript">false and</code> are typically used in conditional statements. You can either create them explicitly
<pre><code class="language-javascript">var alive = true;</code></pre>
```javascript
var alive = true;
```
or by evaluating a [comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators). or by evaluating a [comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators).
```javascript <pre><code class="language-javascript">
var dead = false; var dead = false;
var isAlive = !dead; var isAlive = !dead;
``` </code></pre>
isAlive equals `true`. isAlive equals <code class="language-javascript">true</code>.
### Array ### <a href="#array" name="array"></a>Array {#array}
An array is a list of items. In Javascript these items can be any data type, even arrays themselves. An array is a list of items. In Javascript these items can be any data type, even arrays themselves.
```javascript <pre><code class="language-javascript">var mixedBag = ['sword', 24, true, [Math.PI, Math.E], 'shield'];</code></pre>
var mixedBag = ['sword', 24, true, [Math.PI, Math.E], 'shield'];
```
To access an item in an array use [] notation with an index as mentioned over at strings. To access an item in an array use [] notation with an index as mentioned over at strings.
```javascript <pre><code class="language-javascript">['sword', 'shield', 'helmet'][1];</code></pre>
['sword', 'shield', 'helmet'][1];
```
Returns `'shield'`. In order to figure out how many items are in the array: Returns <code class="language-javascript">'shield'</code>. to figure out how many items are in the array.
```javascript <pre><code class="language-javascript">
var inventory = ['boots', 'gloves', 'pants', 'shirt']; var inventory = ['boots', 'gloves', 'pants', 'shirt'];
var inventoryAmt = inventory.length; var inventoryAmt = inventory.length;
``` </code></pre>
inventoryAmt is `4` since there are 4 items in inventory. inventoryAmt is <code class="language-javascript">4</code> since there are 4 items in inventory.
#### Array Methods #### <a href="#array-methods" name="array-methods"></a>Array Methods {#array-methods}
##### `Array.prototype.push()` ##### <a href="#array.prototype.push();" name="array.prototype.push();"></a>Array.prototype.push(); {#array.prototype.push();}
Adds whatever is inside the parenthesis to the end of the array. Great for adding items to a list. For example, test scores. Adds whatever is inside the parenthesis to the end of the array. Great for adding items to a list. For example, test scores.
```javascript <pre><code class="language-javascript">[100,92,95].push(80);</code></pre>
[100,92,95].push(80);
```
Returns `[100,92,95,80]`. Returns <code class="language-javascript">[100,92,95,80]</code>.
##### `Array.prototype.reverse()` ##### <a href="#array.prototype.reverse();" name="array.prototype.reverse();"></a>Array.prototype.reverse(); {#array.prototype.reverse();}
Reverses the order of all the items in the array. Reverses the order of all the items in the array.
```javascript <pre><code class="language-javascript">[1,2,3].reverse();</code></pre>
[1,2,3].reverse();
```
Returns `[3,2,1]`. Returns <code class="language-javascript">[3,2,1]</code>.
##### `Array.prototype.concat()` ##### <a href="#array.prototype.concat();" name="array.prototype.concat();"></a>Array.prototype.concat(); {#array.prototype.concat();}
Combines two arrays, putting the items from the array in the parenthesis to the end of the main array. This method is a lot faster than grabbing each item by their index and adding them using the `.push()` method. Combines two arrays, putting the items from the array in the parenthesis to the end of the main array. This method is a lot faster than grabbing each item by their index and adding them using the .push() method.
```javascript <pre><code class="language-javascript">['a','b','c'].concat([1,2,3]);</code></pre>
['a','b','c'].concat([1,2,3]);
```
Returns `['a','b','c',1,2,3]`. Returns <code class="language-javascript">['a','b','c',1,2,3]</code>.
##### `Array.prototype.join()` ##### <a href="#array.prototype.join();" name="array.prototype.join();"></a>Array.prototype.join(); {#array.prototype.join();}
Converts the array into a string, with each item seperated by whatever is in the parenthesis. Useful for telling the user the items in their inventory, for example. Converts the array into a string, with each item seperated by whatever is in the parenthesis. Useful for telling the user the items in their inventory, for example.
```javascript <pre><code class="language-javascript">
var inventory = ['books','apples','pencils']; var inventory = ['books','apples','pencils'];
console.log("You have " + inventory.join(", ") + " in your inventory."); console.log("You have " + inventory.join(", ") + " in your inventory.");
``` </code></pre>
Logs `"You have books, apples, pencils in your inventory."` Logs <code class="language-javascript">"You have books, apples, pencils in your inventory."</code>
##### `Array.prototype.indexOf()` ##### <a href="#array.prototype.indexof();" name="array.prototype.indexof();"></a>Array.prototype.indexOf(); {#array.prototype.indexof();}
Similar to String.prototype.indexOf(), it returns the index of the item inside the parenthesis. Similar to String.prototype.indexOf(), it returns the index of the item inside the parenthesis.
```javascript <pre><code class="language-javascript">['chicken','pizza','tacos'].indexOf('tacos');</code></pre>
['chicken','pizza','tacos'].indexOf('tacos');
```
Returns `2`. Returns <code class="language-javascript">2</code>.
### Objects ### <a href="#objects" name="objects"></a>Objects {#objects}
Objects are like arrays, however theyre easier for establishing the relationship between properties and their values. You can store any data type as a property of an object. Objects are like arrays, however theyre easier for establishing the relationship between properties and their values. You can store any data type as a property of an object.
```javascript <pre><code class="language-javascript">
var player = {}; var player = {};
player.name = "Brandon"; player.name = "Brandon";
player.health = Number.POSITIVE_INFINITY; player.health = Number.POSITIVE_INFINITY;
console.log(player.name + " has " + player.health + " health."); console.log(player.name + " has " + player.health + " health.");
``` </code></pre>
Logs `"Brandon has Infinity health"`. Yup that sounds about right. Logs <code class="language-javascript">"Brandon has Infinity health"</code> Yup that sounds about right.
### Conclusion ### <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
All of the different data types in Javascript are tools for you to get the job done. When assigning a variable, think to yourself which tool you should use. I had fun doing this lecture. We finished earlier than expected, due to my extra preparations. (Still shuddering over my unpreparedness from last week). We had finished so early in fact, that I went ahead and started teaching next week's material. Do not worry though, my lovely readers only get the most structured of lesson materials. So you'll have to wait until next week to hear more. 🙂 All of the different data types in Javascript are tools for you to get the job done. When assigning a variable, think to yourself which tool you should use. I had fun doing this lecture. We finished earlier than expected, due to my extra preparations. (Still shuddering over my unpreparedness from last week). We had finished so early in fact, that I went ahead and started teaching next week&#8217;s material. Do not worry though, my lovely reader&#8217;s only get the most structured of lesson materials. So you&#8217;ll have to wait until next week to hear more. 🙂

View file

@ -19,7 +19,7 @@ Hello everyone! This is part 5 of my series on animation. Todays post will be
<!--more--> <!--more-->
Ill give a shout-out to [http://csstriggers.com](http://csstriggers.com), if you are interested in [CSS Animation performance](https://blogs.adobe.com/webplatform/2014/03/18/css-animations-and-transitions-performance/), then check them out to see what triggers a repaint and/or reflow. Take a look at the other posts in this series! Ill give a shout-out to <http://csstriggers.com>, if you are interested in [CSS Animation performance](https://blogs.adobe.com/webplatform/2014/03/18/css-animations-and-transitions-performance/), then check them out to see what triggers a repaint and/or reflow. Take a look at the other posts in this series!
* Part 1 — [Animatable: Border](https://brandonrozek.com/2015/05/animatable-border/) * Part 1 — [Animatable: Border](https://brandonrozek.com/2015/05/animatable-border/)
* Part 2 — [Animatable: Box Model](https://brandonrozek.com/2015/09/animatable-box-model/) * Part 2 — [Animatable: Box Model](https://brandonrozek.com/2015/09/animatable-box-model/)
@ -28,63 +28,88 @@ Ill give a shout-out to [http://csstriggers.com](http://csstriggers.com), if
This post goes with a [Codepen demo](http://codepen.io/brandonrozek/full/rOzeyO/){.broken_link} I made, Ill reference it later in this post. This post goes with a [Codepen demo](http://codepen.io/brandonrozek/full/rOzeyO/){.broken_link} I made, Ill reference it later in this post.
### Color ### <a href="#color" name="color"></a>color {#color}
* Accepts any [color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) value * Accepts any [color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) value
* Typically inherits its color from the parent element * Typically inherits it&#8217;s color from the parent element
The color property sets the color of an elements text content and its decoration. During the animation, the browser sees the colors in their red, green, and blue (rgb) components, then increments/decrements those values until it reaches the color its animating to. For example, in the Codepen demo (#1), the color of the text is changing from `red` or `rgb(255, 0, 0)` to `green` or `rgb(0, 255, 0)`. Meaning the red component is going from 255 to 0 and the green component is going from 0 to 255 during the animation. The color property sets the color of an elements text content and its decoration. During the animation, the browser sees the colors in their red, green, and blue (rgb) components, then increments/decrements those values until it reaches the color its animating to. For example, in the Codepen demo (#1), the color of the text is changing from <code class="language-css">red</code> or <code class="language-css">rgb(255, 0, 0)</code> to <code class="language-css">green</code> or <code class="language-css">rgb(0, 255, 0)</code>. Meaning the red component is going from 255 to 0 and the green component is going from 0 to 255 during the animation.
<pre><code class="language-css">@keyframes color {
```css
@keyframes color {
to { color: green; } to { color: green; }
} }
.color { .color {
font-size: 2rem;
color: red;
text-decoration: underline;
animation: color 1.5s ease-in 0s infinite alternate;
}
```
### opacity font-size: 2rem;
color: red;
text-decoration: underline;
animation: color 1.5s ease-in 0s infinite alternate;
}
</code></pre>
### <a href="#opacity" name="opacity"></a>opacity {#opacity}
* Accepts any number from [0, 1] * Accepts any number from [0, 1]
* Initial Value: 1 * Initial Value: 1
Opacity sets the transparency of an element and its decendants. Unlike `display: none;`, when the element is `opacity: 0;` the element still holds its space on the page. In the Codepen demo (#2), you can see the element and its children fading out. Opacity sets the transparency of an element and its decendants. Unlike <code class="language-css">display: none;</code>, when the element is <code class="language-css">opacity: 0;</code> the element still holds its space on the page. In the Codepen demo (#2), you can see the element and its children fading out.
<pre><code class="language-css">@keyframes opacity {
```css
@keyframes opacity {
to { opacity: 0; } to { opacity: 0; }
} }
.opacity { .opacity {
height: 5rem; height: 5rem;
width: 5rem; width: 5rem;
background-color: #cd86e4; background-color: #cd86e4;
opacity: 1; opacity: 1;
animation: opacity 2s linear 0s infinite alternate; animation: opacity 2s linear 0s infinite alternate;
} }
.opacity div { .opacity div {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
height: 3rem; height: 3rem;
width: 3rem; width: 3rem;
background-color: lightblue; background-color: lightblue;
} }
.opacity div div { .opacity div div {
margin-left: auto;
margin-right: auto;
height: 1rem;
width: 1rem;
background-color: #00b300;
}
```
### Conclusion margin-left: auto;
margin-right: auto;
height: 1rem;
width: 1rem;
background-color: #00b300;
}
</code></pre>
### <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
I used to work on a chat application called Babbler. In it, I used opacity to fade in the messages as the user recieved them. With all these different types of animations, you can visually show the user whats going on in your website/application. Doing this series helps me, (as well as you, I hope) recognize all the different properties and possibilities for animation. This is the second to last part of this series, meaning that the next part is the finale. Im somewhat sad to see this series ending but excited at the same time. Until next time, have fun animating. 🙂 I used to work on a chat application called Babbler. In it, I used opacity to fade in the messages as the user recieved them. With all these different types of animations, you can visually show the user whats going on in your website/application. Doing this series helps me, (as well as you, I hope) recognize all the different properties and possibilities for animation. This is the second to last part of this series, meaning that the next part is the finale. Im somewhat sad to see this series ending but excited at the same time. Until next time, have fun animating. 🙂

View file

@ -29,83 +29,112 @@ This is not a comprehensize list. If you want one of those, please check out MDN
Animatable: Transform goes with a [CodePen demo](http://codepen.io/brandonrozek/full/ojoMyE){.broken_link} I made. Please check it out, as I will be referencing it later on in the post. Animatable: Transform goes with a [CodePen demo](http://codepen.io/brandonrozek/full/ojoMyE){.broken_link} I made. Please check it out, as I will be referencing it later on in the post.
### rotate() ### <a href="#rotate()" name="rotate()"></a>rotate() {#rotate()}
The rotate() function moves the element around a fixed point as defined by the [transform-origin](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin) property. In the Codepen demo (#1), the star continously rotates 360 degrees. The rotate() function moves the element around a fixed point as defined by the [transform-origin](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin) property. In the Codepen demo (#1), the star continously rotates 360 degrees.
```css <pre><code class="language-css">@keyframes rotate {
@keyframes rotate {
to { transform: rotate(360deg);} to { transform: rotate(360deg);}
} }
.rotate { .rotate {
width: 6rem; width: 6rem;
height: 6rem; height: 6rem;
background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Star_full.svg/2000px-Star_full.svg.png"); background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Star_full.svg/2000px-Star_full.svg.png");
background-size: cover; background-size: cover;
transform: none; transform: none;
animation: rotate 1s ease 0s infinite; animation: rotate 1s ease 0s infinite;
} }
``` </code></pre>
### scale() ### <a href="#scale()" name="scale()"></a>scale() {#scale()}
Scale(sx, sy) modifies the size of the element by taking 2 arguments: sx and sy. Where sx is the multiplier that scales the element in the x-direction while sy is the multiplier that scales the element in the y-direction. In the CodePen demo (#2), the little ninja man scales to half his size and back to normal again. Scale(sx, sy) modifies the size of the element by taking 2 arguments: sx and sy. Where sx is the multiplier that scales the element in the x-direction while sy is the multiplier that scales the element in the y-direction. In the CodePen demo (#2), the little ninja man scales to half his size and back to normal again.
```css <pre><code class="language-css">@keyframes scale {
@keyframes scale {
to { transform: scale(.5); } to { transform: scale(.5); }
} }
.scale { .scale {
width: 6rem; width: 6rem;
height: 6rem; height: 6rem;
background-image: url("https://upload.wikimedia.org/wikipedia/commons/7/71/Monocromaticman.JPG"); background-image: url("https://upload.wikimedia.org/wikipedia/commons/7/71/Monocromaticman.JPG");
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
transform: none; transform: none;
animation: scale 1s ease 0s infinite alternate; animation: scale 1s ease 0s infinite alternate;
} }
``` </code></pre>
### skew() ### <a href="#skew()" name="skew()"></a>skew() {#skew()}
Skew distorts the element by moving each point to a certain angle determined by its distance from the origin. In the CodePen demo (#3), the square skews -20 degrees, making it appear as a parallelogram. Skew distorts the element by moving each point to a certain angle determined by its distance from the origin. In the CodePen demo (#3), the square skews -20 degrees, making it appear as a parallelogram.
```css <pre><code class="language-css">@keyframes skew {
@keyframes skew {
to { transform: skew(-20deg); } to { transform: skew(-20deg); }
} }
.skew { .skew {
height: 6rem; height: 6rem;
width: 6rem; width: 6rem;
background-color: lightblue; background-color: lightblue;
transform: none; transform: none;
animation: skew .75s ease 0s infinite alternate; animation: skew .75s ease 0s infinite alternate;
} }
``` </code></pre>
### translate() ### <a href="#translate()" name="translate()"></a>translate() {#translate()}
Transform(tx, ty) moves the element as specified by its two parameters tx and ty. Tx tells the browser how many units to move it in the x direction while ty tells the browser how many units to move the element in the y direction. In the CodePen demo (#4), the car moves forward 10rem and back again. Transform(tx, ty) moves the element as specified by its two parameters tx and ty. Tx tells the browser how many units to move it in the x direction while ty tells the browser how many units to move the element in the y direction. In the CodePen demo (#4), the car moves forward 10rem and back again.
```css <pre><code class="language-css">@keyframes translate {
@keyframes translate {
to { transform: translate(10rem);} to { transform: translate(10rem);}
} }
.translate { .translate {
height: 6rem; height: 6rem;
width: 6rem; width: 6rem;
background-image: url("http://res.freestockphotos.biz/pictures/15/15685-illustration-of-a-red-cartoon-car-pv.png"); background-image: url("http://res.freestockphotos.biz/pictures/15/15685-illustration-of-a-red-cartoon-car-pv.png");
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
transform: none; transform: none;
animation: translate 1s ease 0s infinite alternate; animation: translate 1s ease 0s infinite alternate;
} }
``` </code></pre>
### Conclusion ### <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
It is now the end of the Animatable series. I am sad to see this first completed series of mine go. Its okay though, Im bound to think of another series to write for you guys in no time. My goal in Animatable, is to show you (and me) what is possible using CSS animations. With this small reference completed, we have a good overview of the different tools available. Now with our new toolbelt, go out and craft meaningful experinces! It is now the end of the Animatable series. I am sad to see this first completed series of mine go. Its okay though, Im bound to think of another series to write for you guys in no time. My goal in Animatable, is to show you (and me) what is possible using CSS animations. With this small reference completed, we have a good overview of the different tools available. Now with our new toolbelt, go out and craft meaningful experinces!

View file

@ -24,9 +24,9 @@ Javascript, like most other programming languages, include ways to run blocks of
This post is part of my lecture series for Math I/O. There is no pre-reading for this lecture. This post is part of my lecture series for Math I/O. There is no pre-reading for this lecture.
### If Statement ### <a href="#if-statement" name="if-statement"></a>If Statement {#if-statement}
To run a block of code when a condition is true, use an `if` statement. To run a block of code when a condition is true, use an <code class="language-javascript">if</code> statement.
```javascript ```javascript
if (condition) { if (condition) {
@ -34,7 +34,7 @@ if (condition) {
} }
``` ```
You can also run a block of code when a condition is false using the `else` statement. You can also run a block of code when a condition is false using the <code class="language-javascript">else</code> statement.
```javascript ```javascript
if (condition) { if (condition) {
@ -44,9 +44,9 @@ if (condition) {
} }
``` ```
### Switch statement ### <a href="#switch-statement" name="switch-statement"></a>Switch statement {#switch-statement}
If you want to check a variable for **equality** against multiple different cases, use a `switch` statement. If you want to check a variable for **equality** against multiple different cases, use a <code class="language-javascript">switch</code> statement.
```javascript ```javascript
switch (variable) { switch (variable) {
@ -64,9 +64,9 @@ switch (variable) {
The default statement runs when the variable doesnt equal any of the cases. The default statement runs when the variable doesnt equal any of the cases.
### While loop ### <a href="#while-loop" name="while-loop"></a>While loop {#while-loop}
To run a block of code over and over again until a condition is false, use a `while` loop. To run a block of code over and over again until a condition is false, use a <code class="language-javascript">while</code> loop.
```javascript ```javascript
while (condition) { while (condition) {
@ -74,11 +74,11 @@ while (condition) {
} }
``` ```
Dont forget to include something in the loop that will eventually make the condition `false`, otherwise you run into an infinite loop. (Which is a loop that never stops repeating itself; most likely crashing your browser) Dont forget to include something in the loop that will eventually make the condition <code class="language-javascript">false</code>, otherwise you run into an infinite loop. (Which is a loop that never stops repeating itself; most likely crashing your browser)
### For loop ### <a href="#for-loop" name="for-loop"></a>For loop {#for-loop}
If you want to run something a certain amount of times, use a `for` loop. For loops can be broken down into three components: an initiating statement, a condition, and a statement that runs after every loop. If you want to run something a certain amount of times, use a &#8220;<code class="language-javascript">for"</code> loop. For loops can be broken down into three components: an initiating statement, a condition, and a statement that runs after every loop.
```javascript ```javascript
for (var i = 0; i &lt; 5; i++) { for (var i = 0; i &lt; 5; i++) {
@ -86,9 +86,9 @@ for (var i = 0; i &lt; 5; i++) {
} }
``` ```
Here you have the initiating statement of `var i = 0`. From there you check, is `i` less than 5? Yes, so then we `doSomething();`. After we `doSomething();`, we add 1 to `i`. Now `i` equals 2. Is`i` still less than 5? Yes, so we `doSomething();`. Then we add 1 to `i` again. This loop will keep happening until `i` is not less than 5. Here you have the initiating statement of <code class="language-javascript">var i = 0</code>. From there you check, is <code class="language-javascript">i</code> less than 5? Yes, so then we <code class="language-javascript">doSomething();</code>. After we <code class="language-javascript">doSomething();</code>, we add 1 to <code class="language-javascript">i</code>. Now <code class="language-javascript">i</code> equals 2. Is <code class="language-javascript">i</code> still less than 5? Yes, so we <code class="language-javascript">doSomething();</code>. Then we add 1 to <code class="language-javascript">i</code> again. This loop will keep happening until <code class="language-javascript">i</code> is not less than 5.
### Conclusion ### <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
Having different control/conditional statements helps keep the state of any application youre making. Did the user say not to notify them? Then dont, otherwise (else) notify them. Thats all I have to say for this week. Hope this post helps you get a little more used to this big world called programming. Having different control/conditional statements helps keep the state of any application youre making. Did the user say not to notify them? Then dont, otherwise (else) notify them. Thats all I have to say for this week. Hope this post helps you get a little more used to this big world called programming.

View file

@ -17,7 +17,9 @@ tags: ["Web", "JS"]
--- ---
Ever had a snippet of code that appears multiple times in different places in your program? Whenever you had to change that snippet, you end up playing this game of search and replace. Functions can help. They exist to abstract your code, making it not only easier to change that little snippet, but to read and debug your code as well. Ever had a snippet of code that appears multiple times in different places in your program? Whenever you had to change that snippet, you end up playing this game of search and replace. Functions can help. They exist to abstract your code, making it not only easier to change that little snippet, but to read and debug your code as well.
### How to create/execute a function <!--more-->
### <a href="#how-to-create/execute-a-function" name="how-to-create/execute-a-function"></a>How to create/execute a function {#how-to-create/execute-a-function}
To make a function To make a function
@ -33,7 +35,7 @@ To call the above function to execute
doSomething(); doSomething();
``` ```
### Arguments ### <a href="#arguments" name="arguments"></a>Arguments {#arguments}
You can also add in arguments (parameters that go inside the paraenthesis next to the word function) for the functions to use. You can also add in arguments (parameters that go inside the paraenthesis next to the word function) for the functions to use.
@ -49,13 +51,13 @@ And when you use the `return` keyword, like the function above. You can store th
var total = add(1, 3); var total = add(1, 3);
``` ```
`total` here will equal `4` <code class="language-javascript">total</code> here will equal `4`
### Scope ### <a href="#scope" name="scope"></a>Scope {#scope}
Functions create their own scope, which means that variables created inside the function will only be able available within that function. Functions create their own scope, which means that variables created inside the function will only be able available within that function.
The snippet below will output an error like `total is not defined`. The snippet below will output an error like <code class="language-javascript">total is not defined</code>
```javascript ```javascript
var add = function(number1, number2) { var add = function(number1, number2) {
@ -78,7 +80,7 @@ Below is a correct example of the concept
Its also important to note that functions can use variables outside of it; granted it resides in the same scope. Its also important to note that functions can use variables outside of it; granted it resides in the same scope.
Here is an example of a variable that doesn't reside in the same scope as the function. (The below code will fail) Here is an example of a variable that doesn&#8217;t reside in the same scope as the function. (The below code will fail)
```javascript ```javascript
var something = function() { var something = function() {
@ -102,8 +104,8 @@ Below, is an example of where the variable does reside in the same scope as the
var sum = addX(6); var sum = addX(6);
``` ```
`sum` here will equal `11` <code class="language-javascript">sum</code> here will equal <code class="language-javascript">11</code>
### Conclusion ### <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
As long as you name them appropriately, functions are useful for abstracting your code, making them easier to understand. This concludes another lecture made for the members over at Math I/O. Until next week 🙂 As long as you name them appropriately, functions are useful for abstracting your code, making them easier to understand. This concludes another lecture made for the members over at Math I/O. Until next week 🙂

View file

@ -62,7 +62,7 @@ var offlineFundamentals = [
``` ```
Since `cache.addAll()` hasnt been implemented yet in any of the browsers, and the polyfill implementation didnt work for my needs. I pieced together my own. Since <code class="language-javascript">cache.addAll()</code> hasnt been implemented yet in any of the browsers, and the polyfill implementation didnt work for my needs. I pieced together my own.
```javascript ```javascript
var updateStaticCache = function() { var updateStaticCache = function() {
@ -85,8 +85,8 @@ var updateStaticCache = function() {
Lets go through this chunk of code. Lets go through this chunk of code.
1. Open the cache called `'v2.0.24:fundamentals'` 1. Open the cache called <code class="language-javascript">'v2.0.24:fundamentals'</code>
2. Go through all of the `offlineFundamental`s URLs 2. Go through all of the <code class="language-javascript">offlineFundamental</code>s URLs
* Does the file I ask for come from the same domain as my site? * Does the file I ask for come from the same domain as my site?
* No. Then, make the request no-cors (I had difficulty getting my asset files in cors mode. If the cors headers are included in the response, then you can take out this line) * No. Then, make the request no-cors (I had difficulty getting my asset files in cors mode. If the cors headers are included in the response, then you can take out this line)
* Fetch the file from the network and then cache it. * Fetch the file from the network and then cache it.
@ -140,7 +140,7 @@ self.addEventListener("activate", function(event) {
The cool thing about service workers is that it can handle file requests. We could cache all files requested for offline use, and if a fetch for a resource failed, then the service worker can look for it in the cache or provide an alternative. This is a large section, so Im going to attempt to break it down as much as I can. The cool thing about service workers is that it can handle file requests. We could cache all files requested for offline use, and if a fetch for a resource failed, then the service worker can look for it in the cache or provide an alternative. This is a large section, so Im going to attempt to break it down as much as I can.
## Limit the cache ## Limit the cache {#limit-the-cache}
If the visitor started browsing all of the pages on my site, his or her cache would start to get bloated with files. To not burden my visitors, I decided to only keep the latest 25 pages and latest 10 images in the cache. If the visitor started browsing all of the pages on my site, his or her cache would start to get bloated with files. To not burden my visitors, I decided to only keep the latest 25 pages and latest 10 images in the cache.
@ -159,7 +159,7 @@ Well call it later in the code.
## Fetch from network and cache ## Fetch from network and cache
Every time I fetch a file from the network I throw it into a specific cache container: `'pages'` for HTML files, `'images'` for CSS files, and `'assets'` for any other file. This is so I can handle the cache limiting above easier. Defined within the `fetch` event. Every time I fetch a file from the network I throw it into a specific cache container. <code class="language-javascript">'pages'</code> for HTML files, <code class="language-javascript">'images'</code> for CSS files, and <code class="language-javascript">'assets'</code> for any other file. This is so I can handle the cache limiting above easier. Defined within the `fetch` event.
```javascript ```javascript
var fetchFromNetwork = function(response) { var fetchFromNetwork = function(response) {

View file

@ -15,19 +15,19 @@ mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}' - 'a:1:{s:6:"author";a:0:{}}'
tags: ["JS"] tags: ["JS"]
--- ---
Last week I published my first library over on Github called [Fractions.js](https://github.com/brandonrozek/Fractions.js). Fractions.js is a library to help avoid the [mathmatetical errors](http://floating-point-gui.de/) in floating point arithmetic. What do you mean by floating point artihmetic errors? Here is an example: `.1 * .2` outputs `0.020000000000000004` even though the correct answer is `.02`. Last week I published my first library over on Github called [Fractions.js](https://github.com/brandonrozek/Fractions.js). Fractions.js is a library to help avoid the [mathmatetical errors](http://floating-point-gui.de/) in floating point arithmetic. What do you mean by floating point artihmetic errors? Here is an example: <code class="language-javascript">.1 * .2</code> outputs <code class="language-javascript">0.020000000000000004</code> even though the correct answer is <code class="language-javascript">.02</code>
<!--more--> <!--more-->
## Purpose ## <a href="#purpose" name="purpose"></a>Purpose {#purpose}
My team and I are currently working on a new game for Math I/O. One of the levels is testing whether the player can add, subtract, multiply, and divide fractions correctly. I didnt want to implement a solution where we check if the input entered is within a range of the answer. So I asked the team, how do you add, subtract, multiply, and divide fractions in your head? As we were working through it together, I realized that this is a common problem over at Math I/O. So I decided to make a library dedicated to this. My team and I are currently working on a new game for Math I/O. One of the levels is testing whether the player can add, subtract, multiply, and divide fractions correctly. I didnt want to implement a solution where we check if the input entered is within a range of the answer. So I asked the team, how do you add, subtract, multiply, and divide fractions in your head? As we were working through it together, I realized that this is a common problem over at Math I/O. So I decided to make a library dedicated to this.
## How it works ## <a href="#how-it-works" name="how-it-works"></a>How it works {#how-it-works}
I broke up each fraction into two things, a numerator and a denominator. With these two numbers, I can figure out all of the most common operations. I broke up each fraction into two things, a numerator and a denominator. With these two numbers, I can figure out all of the most common operations.
### Addition ### <a href="#addition" name="addition"></a>Addition {#addition}
For addition, if two fractions have the same denominator, then you just need to add the numerators. For addition, if two fractions have the same denominator, then you just need to add the numerators.
@ -39,66 +39,66 @@ If not, then you need to change it to have a common denominator. We can do this
1/2 + 1/3 = (1 * 3)/ (2 * 3) + (1 * 2)/ (2 * 3) = 3/6 + 2/6 = 5/6 1/2 + 1/3 = (1 * 3)/ (2 * 3) + (1 * 2)/ (2 * 3) = 3/6 + 2/6 = 5/6
### Subtraction ### <a href="#subtraction" name="subtraction"></a>Subtraction {#subtraction}
Works the same as addition, except the second fraction is subtracted (taken away) from the first. Works the same as addition, except the second fraction is subtracted (taken away) from the first.
### Multiplication ### <a href="#multiplication" name="multiplication"></a>Multiplication {#multiplication}
To multiply two fractions, just multiply the numerators by each other, and the denominators by each other. To multiply two fractions, just multiply the numerators by each other, and the denominators by each other.
2/3 * 1/2 = 2/6 2/3 * 1/2 = 2/6
### Division ### <a href="#division" name="division"></a>Division {#division}
Treated similar to multiplication since dividing a number is the same thing as multiplying by its [reciprocal](https://www.mathsisfun.com/reciprocal.html). Treated similar to multiplication since dividing a number is the same thing as multiplying by its [reciprocal](https://www.mathsisfun.com/reciprocal.html).
1 / (1 / 2) = 1 * 2 = 2 1 / (1 / 2) = 1 * 2 = 2
### Simplification ### <a href="#simplification" name="simplification"></a>Simplification {#simplification}
Sometimes with the operations above, itll produce fractions in an unsimplified form. To avoid any confusion, I created a simplify function. It was challanging trying to figure out a way to code this. While I was browsing around for an implementation, I knocked into Eucliders algorithm for finding the greatest common factor. Straight from the [Wikipedia article](https://en.wikipedia.org/wiki/Euclidean_algorithm) (where a is greater than b): Sometimes with the operations above, itll produce fractions in an unsimplified form. To avoid any confusion, I created a simplify function. It was challanging trying to figure out a way to code this. While I was browsing around for an implementation, I knocked into Eucliders algorithm for finding the greatest common factor. Straight from the [Wikipedia article](https://en.wikipedia.org/wiki/Euclidean_algorithm) (where a is greater than b):
```
function gcd(a, b) function gcd(a, b)
while b ≠ 0 while b ≠ 0
t := b; t := b;
b := a mod b; b := a mod b;
a := t; a := t;
return a; return a;
```
I can then simplify the fraction by dividing the numerator and denominator by the greatest common factor. I can then simplify the fraction by dividing the numerator and denominator by the greatest common factor.
## The API ## <a href="#the-api" name="the-api"></a>The API {#the-api}
I decided to provide as much flexibility as I can in the API. You have several ways to create a new Fraction. I decided to provide as much flexibility as I can in the API. You have several ways to create a new Fraction.
```javascript <pre><code class="language-javascript">
var oneHalf = new Fraction(1,2); var oneHalf = new Fraction(1,2);
var oneHalf = new Fraction(.5); var oneHalf = new Fraction(.5);
var oneHalf = new Fraction("1/2"); var oneHalf = new Fraction("1/2");
var oneHalf = new Fraction("1", "2"); var oneHalf = new Fraction("1", "2")
``` </code></pre>
All of these results will return a Fraction with a numerator of `1` and a denominator of `2`. You also have two different ways to do the most common operations. All of these results will return a Fraction with a numerator of <code class="language-javascript">1</code> and a denominator of <code class="language-javascript">2</code>. You also have two different ways to do the most common operations.
```javascript <pre><code class="language-javascript">
var fiveThirds = Fraction.add("1/3", "4/3"); var fiveThirds = Fraction.add("1/3", "4/3");
var fiveThirds = new Fraction("1/3").add("4/3"); var fiveThirds = new Fraction("1/3").add("4/3");
``` </code></pre>
The second style came from how jQuery implements its library. That way you can chain operations. The second style came from how jQuery implements its library. That way you can chain operations.
```javascript <pre><code class="language-javascript">
new Fraction("1/2").add("2/3").divide("5/6").subtract("7/8").multiply("6/5").toString() new Fraction("1/2").add("2/3").divide("5/6").subtract("7/8").multiply("6/5").toString()
``` </code></pre>
Outputs `'63/100'` This is accomplished in the code through [prototypes](http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/). Outputs <code class="language-javascript">'63/100'</code> This is accomplished in the code through [prototypes](http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/).
```javascript <pre><code class="language-javascript">
Fraction.add = function(frac1, frac2) { Fraction.add = function(frac1, frac2) {
Fraction.correctArgumentLength(2, arguments.length); Fraction.correctArgumentLength(2, arguments.length);
frac1 = Fraction.toFraction(frac1) frac1 = Fraction.toFraction(frac1)
@ -113,10 +113,10 @@ Fraction.prototype.add = function(frac) {
Fraction.correctArgumentLength(1, arguments.length); Fraction.correctArgumentLength(1, arguments.length);
return Fraction.change(this, Fraction.add(this, frac)); return Fraction.change(this, Fraction.add(this, frac));
} }
``` </code></pre>
In the code, the add prototype calls the Fraction.add function within it to avoid code duplication. In the code, the add prototype calls the Fraction.add function within it to avoid code duplication.
## Conclusion ## <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
After I coded this up, I looked online for different implementations and found [fraction.js](https://github.com/ekg/fraction.js) by [Erik Garrison](http://hypervolu.me/~erik/). Its important to look at different implementations and see which matches your needs better. This post isnt meant to go fully into detail of the library. To know what else the library can do, visit the [readme page](https://github.com/brandonrozek/Fractions.js/blob/master/README.md). If youre curious in how its implemented, check out the [code](https://github.com/brandonrozek/Fractions.js/blob/master/Fraction.js). [Email me](mailto:brozek@brandonrozek.com) if you have any questions/criticisms 🙂 After I coded this up, I looked online for different implementations and found [fraction.js](https://github.com/ekg/fraction.js) by [Erik Garrison](http://hypervolu.me/~erik/). Its important to look at different implementations and see which matches your needs better. This post isnt meant to go fully into detail of the library. To know what else the library can do, visit the [readme page](https://github.com/brandonrozek/Fractions.js/blob/master/README.md). If youre curious in how its implemented, check out the [code](https://github.com/brandonrozek/Fractions.js/blob/master/Fraction.js). [Email me](mailto:brozek@brandonrozek.com) if you have any questions/criticisms 🙂

View file

@ -18,21 +18,26 @@ bridgy_syndication:
https://twitter.com/B_RozekJournal/status/790337750280970241 https://twitter.com/B_RozekJournal/status/790337750280970241
--- ---
Looking at Aaron Parecki's [&#8220;Fun with QR Codes&#8221;](https://aaronparecki.com/articles/2015/10/05/1/fun-with-qr-codes) inspired me to play with QR Codes myself. Using the tool [QArt Coder](http://research.swtch.com/qr/draw) made by [Russ Cox](https://plus.google.com/116810148281701144465), I made a QR Code with my face in it! Looking at Aaron Parecki&#8217;s [&#8220;Fun with QR Codes&#8221;](https://aaronparecki.com/articles/2015/10/05/1/fun-with-qr-codes) inspired me to play with QR Codes myself. Using the tool [QArt Coder](http://research.swtch.com/qr/draw) made by [Russ Cox](https://plus.google.com/116810148281701144465), I made a QR Code with my face in it!
![](/files/images/blog/qrcode-large-1.png) <!--more-->
<img class="alignnone size-medium wp-image-579" src="https://brandonrozek.com/wp-content/uploads/2016/10/qrcode-large-1.png" alt="qrcode-large" width="300" height="300" />
### Why QR Codes? ### Why QR Codes?
QR Codes aren't prevalent in the United States of America. In fact, they're often viewed by technologists as a [joke](http://picturesofpeoplescanningqrcodes.tumblr.com/). But as [Christina Xu](http://www.christinaxu.org/) points out on her Medium post [&#8220;Pictures of Chinese People Scanning QR Codes&#8221;](https://medium.com/chrysaora-weekly/pictures-of-chinese-people-scanning-qr-codes-a564047ec58f), it's not a joke everywhere. In fact, many people actually depend on this humble little QR code to get by in their day. Another story, my family and I go out to eat sometimes. Occasionally, we'll knock into a Heinz Ketchup bottle. QR Codes aren&#8217;t prevalent in the United States of America. In fact, they&#8217;re often viewed by technologists as a [joke](http://picturesofpeoplescanningqrcodes.tumblr.com/). But as [Christina Xu](http://www.christinaxu.org/) points out on her Medium post [&#8220;Pictures of Chinese People Scanning QR Codes&#8221;](https://medium.com/chrysaora-weekly/pictures-of-chinese-people-scanning-qr-codes-a564047ec58f), it&#8217;s not a joke everywhere. In fact, many people actually depend on this humble little QR code to get by in their day. Another story, my family and I go out to eat sometimes. Occasionally, we&#8217;ll knock into a Heinz Ketchup bottle.
![Picture of Heinz ketch bottle with QR Code](/files/images/blog/heinz-2-768x1024.jpg) <div id="attachment_573" style="width: 235px" class="wp-caption aligncenter">
<img aria-describedby="caption-attachment-573" class="size-medium wp-image-573" src="https://brandonrozek.com/wp-content/uploads/2016/10/heinz-2-768x1024.jpg" alt="Picture of Heinz ketchup bottle with QR Code." width="225" height="300" />
Image by Azad Zahoory. <p id="caption-attachment-573" class="wp-caption-text">
Picture by <a href="http://azadzahoory.com/2014/07/03/when-the-product-becomes-an-ad/">Azad Zahoory</a>
</p>
</div> My brother would get so excited whenever he saw this. This little ketchup bottle meant that we got to play a
My brother would get so excited whenever he saw this. This little ketchup bottle meant that we got to play a [trivia game](http://www.heinztablegames.com/game_selector.html). No matter what you think of QR Codes, vanity or not, there are people who use it every day. So have some fun and make yourself a QR Code of your own. You know, just in case 😉 <a href="http://www.heinztablegames.com/game_selector.html" rel="nofollow" class="broken_link">trivia game</a>. No matter what you think of QR Codes, vanity or not, there are people who use it every day. So have some fun and make yourself a QR Code of your own. You know, just in case 😉
### Setting up the QR Code ### Setting up the QR Code
First, you need a picture. I used a picture of myself. Then for the QArt Coder site to work correctly, the image needs to be in high-contrast. Meaning, it needs to be mostly black and white. To accomplish this, fire up [Gimp](https://www.gimp.org/) (or your image editor of choice), and hit Color -> Threshold. That will give you a black and white version of the picture where you can then play around with the slider to get it just how you want it. After that, open up [QArt Coder](http://research.swtch.com/qr/draw) and upload the image onto the site. Once that's accomplished, you might need to play with the QR Size, Image Size, Rotation, and other options. After that, hit &#8220;Save this QR Code&#8221; and viola! You got yourself three different sizes of QR codes to use. What should you do with the QR Code after you get it? First, brag to your friends about how cool it looks. Then maybe put it on your [business card](https://www.webdesignerdepot.com/2011/07/30-creative-qr-code-business-cards/). If you can think of any other ~~excuses~~ uses of QR Codes [contact me](mailto:brozek@brandonrozek.com) 🙂 First, you need a picture. I used a picture of myself. Then for the QArt Coder site to work correctly, the image needs to be in high-contrast. Meaning, it needs to be mostly black and white. To accomplish this, fire up [Gimp](https://www.gimp.org/) (or your image editor of choice), and hit Color -> Threshold. That will give you a black and white version of the picture where you can then play around with the slider to get it just how you want it. After that, open up [QArt Coder](http://research.swtch.com/qr/draw) and upload the image onto the site. Once that&#8217;s accomplished, you might need to play with the QR Size, Image Size, Rotation, and other options. After that, hit &#8220;Save this QR Code&#8221; and viola! You got yourself three different sizes of QR codes to use. What should you do with the QR Code after you get it? First, brag to your friends about how cool it looks. Then maybe put it on your [business card](https://www.webdesignerdepot.com/2011/07/30-creative-qr-code-business-cards/). If you can think of any other <del>excuses</del> uses of QR Codes [contact me](mailto:brozek@brandonrozek.com) 🙂

View file

@ -23,11 +23,11 @@ Microformats is semantic HTML used to convey metadata. Using an userscript, I ca
[H-card](http://microformats.org/wiki/h-card) is a type of microformat that serves as a contact card for people and organizations. [H-card](http://microformats.org/wiki/h-card) is a type of microformat that serves as a contact card for people and organizations.
[vCard](https://en.wikipedia.org/wiki/VCard) is the standard for electronic business cards. They're most likely used in your phone to store contacts. [vCard](https://en.wikipedia.org/wiki/VCard) is the standard for electronic business cards. They&#8217;re most likely used in your phone to store contacts.
Userscript is essentially JavaScript that runs in the [Greasemonkey](http://www.greasespot.net/) extension. Userscript is essentially JavaScript that runs in the [Greasemonkey](http://www.greasespot.net/) extension.
### What I'll need ### What I&#8217;ll need
* Microformat parser * Microformat parser
* Way to find the representative h-card * Way to find the representative h-card
@ -40,7 +40,7 @@ To keep everything in small [reusable components](https://en.wikipedia.org/wiki/
Next, I need to find the representative h-card of the page. Following the [instructions](http://microformats.org/wiki/representative-h-card-parsing) on the microformats wiki, I wrote the following code. Next, I need to find the representative h-card of the page. Following the [instructions](http://microformats.org/wiki/representative-h-card-parsing) on the microformats wiki, I wrote the following code.
```javascript <pre><code class="language-javascript">
/* /*
representative-h-card - v0.1.0 representative-h-card - v0.1.0
Copyright (c) 2015 Brandon Rozek Copyright (c) 2015 Brandon Rozek
@ -60,7 +60,7 @@ var representativeHCard = function(hCards, url) {
hCard.items = [hCards.items[0]]; hCard.items = [hCards.items[0]];
return hCard return hCard
} else { } else {
for (var i = 0; i < hCards.items.length; i++) { for (var i = 0; i &lt; hCards.items.length; i++) {
if (urlsMatchURL(hCards.items[i], url) && (uidsMatchURL(hCards.items[i], url) || relMeMatchURL(hCards, url))) { if (urlsMatchURL(hCards.items[i], url) && (uidsMatchURL(hCards.items[i], url) || relMeMatchURL(hCards, url))) {
hCard = hCards; hCard = hCards;
hCard.items = [hCards.items[i]]; hCard.items = [hCards.items[i]];
@ -75,7 +75,7 @@ var representativeHCard = function(hCards, url) {
var urlsMatchURL = function(hCard, url) { var urlsMatchURL = function(hCard, url) {
var urls = hCard.properties.url; var urls = hCard.properties.url;
if (typeof(urls) == "object") { if (typeof(urls) == "object") {
for (var i = 0; i < urls.length; i++) { for (var i = 0; i &lt; urls.length; i++) {
if (new URL(urls[i]).toString() == new URL(url).toString()) { if (new URL(urls[i]).toString() == new URL(url).toString()) {
return true; return true;
} }
@ -86,7 +86,7 @@ var urlsMatchURL = function(hCard, url) {
var uidsMatchURL = function(hCard, url) { var uidsMatchURL = function(hCard, url) {
var uids = hCard.properties.uid; var uids = hCard.properties.uid;
if (typeof(uids) == "object") { if (typeof(uids) == "object") {
for (var i = 0; i < uids.length; i++) { for (var i = 0; i &lt; uids.length; i++) {
if (new URL(uids[i]).toString() == new URL(url).toString()) { if (new URL(uids[i]).toString() == new URL(url).toString()) {
return true; return true;
} }
@ -97,7 +97,7 @@ var uidsMatchURL = function(hCard, url) {
var relMeMatchURL = function(microformats, url) { var relMeMatchURL = function(microformats, url) {
var me = microformats.rels.me; var me = microformats.rels.me;
if (typeof(me) == "object") { if (typeof(me) == "object") {
for (var i = 0; i < me.length; i++) { for (var i = 0; i &lt; me.length; i++) {
if (new URL(me[i]).toString() == new URL(url).toString()) { if (new URL(me[i]).toString() == new URL(url).toString()) {
return true; return true;
} }
@ -105,9 +105,9 @@ var relMeMatchURL = function(microformats, url) {
} }
return false; return false;
} }
``` </code></pre>
Next up, is making the vCard. For this, I had to look at the [vCard 4.0 specification](https://tools.ietf.org/html/rfc6350) to figure out what the property names and values are. Then I browsed around different [sites](http://indieweb.thatmustbe.us/) (takes you to a random [Indieweb](https://indiewebcamp.com/) site)  to figure out which properties are the most common. Next up, is making the vCard. For this, I had to look at the [vCard 4.0 specification](https://tools.ietf.org/html/rfc6350) to figure out what the property names and values are. Then I browsed around different <a href="http://indieweb.thatmustbe.us/" rel="nofollow">sites</a> (takes you to a random [Indieweb](https://indiewebcamp.com/) site)  to figure out which properties are the most common.
The properties I ended up adding to the vCard. The properties I ended up adding to the vCard.
@ -123,7 +123,7 @@ The properties I ended up adding to the vCard.
 As I was browsing around, I noticed that a few people would have empty values for certain properties on their h-card. To avoid having this show up on the vCard, I added a filter that takes out empty strings.  As I was browsing around, I noticed that a few people would have empty values for certain properties on their h-card. To avoid having this show up on the vCard, I added a filter that takes out empty strings.
```javascript <pre><code class="language-javascript">
/* /*
vCard-from-h-card - v0.1.0 vCard-from-h-card - v0.1.0
Copyright (c) 2015 Brandon Rozek Copyright (c) 2015 Brandon Rozek
@ -180,7 +180,7 @@ var makeVCard = function(hCard) {
//Add IMPP (Instant Messaging and Presence Protocol) //Add IMPP (Instant Messaging and Presence Protocol)
if (typeof(impp) == "object") { if (typeof(impp) == "object") {
impp.removeEmptyStrings(); impp.removeEmptyStrings();
for (var i = 0; i < impp.length; i++) { for (var i = 0; i &lt; impp.length; i++) {
vCard += "IMPP;PREF=" + (i + 1) + ": " + impp[i] + "n"; vCard += "IMPP;PREF=" + (i + 1) + ": " + impp[i] + "n";
} }
} }
@ -189,7 +189,7 @@ var makeVCard = function(hCard) {
var email = hCard.items[0].properties.email; var email = hCard.items[0].properties.email;
if (typeof(email) == "object") { if (typeof(email) == "object") {
email.removeEmptyStrings(); email.removeEmptyStrings();
for (var i = 0; i < email.length; i++) { for (var i = 0; i &lt; email.length; i++) {
try { try {
vCard += "EMAIL: " + new URL(email[i]).pathname + "n"; vCard += "EMAIL: " + new URL(email[i]).pathname + "n";
} catch (e) { } catch (e) {
@ -238,9 +238,10 @@ var makeVCard = function(hCard) {
Array.prototype.removeEmptyStrings = function() { Array.prototype.removeEmptyStrings = function() {
return this.filter(function(i) { return i !== "" }) return this.filter(function(i) { return i !== "" })
} }
```
Now for the final part, making the userscript. Inspired by [Ryan Barret](https://snarfed.org/) and his userscript [Let's Talk,](https://github.com/snarfed/misc/blob/master/userscripts/lets_talk.user.js) this userscript brings all of the above modules together. First it grabs the microformats from the page using microformat-shiv. </code></pre>
Now for the final part, making the userscript. Inspired by [Ryan Barret](https://snarfed.org/) and his userscript [Let&#8217;s Talk,](https://github.com/snarfed/misc/blob/master/userscripts/lets_talk.user.js) this userscript brings all of the above modules together. First it grabs the microformats from the page using microformat-shiv.
For some reason, when I tried filtering it by &#8216;h-card&#8217; it froze my computer. So I wrote my own little filter instead. For some reason, when I tried filtering it by &#8216;h-card&#8217; it froze my computer. So I wrote my own little filter instead.
@ -248,7 +249,7 @@ After I grab the representative h-card from the page using the little module I w
The link is actually a [data uri](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs) that has all of the information of the vCard encoded in it. Depending on your browser, once you click the link you might have to hit CTRL-S to save. The link is actually a [data uri](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs) that has all of the information of the vCard encoded in it. Depending on your browser, once you click the link you might have to hit CTRL-S to save.
```javascript <pre><code class="language-javascript">
/* /*
show-vCard - v0.1.0 show-vCard - v0.1.0
Copyright (c) 2015 Brandon Rozek Copyright (c) 2015 Brandon Rozek
@ -256,8 +257,8 @@ The link is actually a [data uri](https://developer.mozilla.org/en-US/docs/Web/H
*/ */
var filterMicroformats = function(items, filter) { var filterMicroformats = function(items, filter) {
var newItems = []; var newItems = [];
for (var i = 0; i < items.items.length; i++) { for (var i = 0; i &lt; items.items.length; i++) {
for (var k = 0; k < items.items[i].type.length; k++) { for (var k = 0; k &lt; items.items[i].type.length; k++) {
if (filter.indexOf(items.items[i].type[k]) != -1) { if (filter.indexOf(items.items[i].type[k]) != -1) {
newItems.push(items.items[i]); newItems.push(items.items[i]);
} }
@ -305,15 +306,15 @@ var render = function() {
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
render(); render();
}); });
``` </code></pre>
Sadly, I have no way of controlling the file name when you save it so you'll have to manually rename it to something more meaningful than a random string of characters. Also remember to add the extension &#8216;.vcf&#8217; for it to be recognized by some devices. Sadly, I have no way of controlling the file name when you save it so you&#8217;ll have to manually rename it to something more meaningful than a random string of characters. Also remember to add the extension &#8216;.vcf&#8217; for it to be recognized by some devices.
### Conclusion ### Conclusion
Fire up your favorite userscript handling tool and add the [script](https://gist.github.com/brandonrozek/e0153b2733e947fa9c87) in! Of course, since it's pure JavaScript, you can also add it to your own site to serve the same purpose. Fire up your favorite userscript handling tool and add the [script](https://gist.github.com/brandonrozek/e0153b2733e947fa9c87) in! Of course, since it&#8217;s pure JavaScript, you can also add it to your own site to serve the same purpose.
I ran into a small problem loading a contact onto my Android 5.0.2 phone. Apparently, they don't support vCard 4.0 yet so I had to go into the file and change the line that says &#8220;VERSION 4.0&#8221; to &#8220;VERSION 3.0&#8221; which then allowed me to import the file into my contacts. I ran into a small problem loading a contact onto my Android 5.0.2 phone. Apparently, they don&#8217;t support vCard 4.0 yet so I had to go into the file and change the line that says &#8220;VERSION 4.0&#8221; to &#8220;VERSION 3.0&#8221; which then allowed me to import the file into my contacts.
As with all the code I write, feel free to comment/criticize. I love hearing feedback so if you spot anything, [contact me](mailto:brozek@brandonrozek.com) 🙂 As with all the code I write, feel free to comment/criticize. I love hearing feedback so if you spot anything, [contact me](mailto:brozek@brandonrozek.com) 🙂

View file

@ -23,4 +23,4 @@ First go to File->Knit Document. If this is your first time, then it will instal
Once that is downloaded, it will let you choose between three different file formats (HTML, PDF, MS Word). For the purposes of blog posts, I like to output it in HTML so I can copy and paste the code. But for personal use, I like using PDFs Once that is downloaded, it will let you choose between three different file formats (HTML, PDF, MS Word). For the purposes of blog posts, I like to output it in HTML so I can copy and paste the code. But for personal use, I like using PDFs
After you select the file format, hit compile, and voila! A nice neat compiled report is created for you. Here is a [pdf](/files/reports/LifeExpectancy.pdf) example of the report I made. After you select the file format, hit compile, and voila! A nice neat compiled report is created for you. Here is a [pdf](https://brandonrozek.com/wp-content/uploads/2017/03/LifeExpectancy.pdf) example of the report I made.

View file

@ -31,7 +31,7 @@ HA: The random numbers outputted do not follow the uniform distribution
I wrote a small [website](http://share.zeropointshift.com/files/2017/03/random.html) and obtained my data by getting the CSV outputted when I use IE11, Firefox, and Chrome. I wrote a small [website](http://share.zeropointshift.com/files/2017/03/random.html) and obtained my data by getting the CSV outputted when I use IE11, Firefox, and Chrome.
The website works by producing a random number using `Math.random()` between 1 and 1000 inclusive and calls the function 1,000,000 times. Storing its results in a file The website works by producing a random number using <code class='language-javascript'>Math.random()</code> between 1 and 1000 inclusive and calls the function 1,000,000 times. Storing it&#8217;s results in a file
This website produces a file with all the numbers separated by a comma. We want these commas to be replaced by newlines. To do so, we can run a simple command in the terminal This website produces a file with all the numbers separated by a comma. We want these commas to be replaced by newlines. To do so, we can run a simple command in the terminal
@ -41,17 +41,17 @@ grep -oE '[0-9]+' Random.csv &gt; Random_corrected.csv
Do this with all three files and make sure to keep track of which is which. Do this with all three files and make sure to keep track of which is which.
Here are a copy of my files for [Firefox](/data/browser-random/Firefox_corrected.csv), [Chrome](/data/browser-random/Chrome_corrected-1.csv), and [IE11](/data/browser-random/IE11_corrected.csv) Here are a copy of my files for [Firefox](https://brandonrozek.com/wp-content/uploads/2017/03/Firefox_corrected.csv), [Chrome](https://brandonrozek.com/wp-content/uploads/2017/03/Chrome_corrected-1.csv), and [IE11](https://brandonrozek.com/wp-content/uploads/2017/03/IE11_corrected.csv)
## Check Conditions ## Check Conditions
Since we're interested in if the random values occur uniformly, we need to perform a Chi-Square test for Goodness of Fit. With every test comes some assumptions Since we&#8217;re interested in if the random values occur uniformly, we need to perform a Chi-Square test for Goodness of Fit. With every test comes some assumptions
**Counted Data Condition:** The data can be converted from quantatative to count data. <u>Counted Data Condition:</u> The data can be converted from quantatative to count data.
**Independence Assumption:** One random value does not affect another. <u>Independence Assumption:</u> One random value does not affect another.
**Expected Cell Frequency Condition:** The expected counts are going to be 10000 <u>Expected Cell Frequency Condition:</u> The expected counts are going to be 10000
Since all of the conditions are met, we can use the Chi-square test of Goodness of Fit Since all of the conditions are met, we can use the Chi-square test of Goodness of Fit
@ -70,19 +70,19 @@ ie11 = read.csv("~/IE11_corrected.csv", header = F)
hist(ie11$V1, main = "Distribution of Random Values for IE11", xlab = "Random Value") hist(ie11$V1, main = "Distribution of Random Values for IE11", xlab = "Random Value")
``` ```
![](/files/images/blog/ie11hist.png) ![](https://brandonrozek.com/wp-content/uploads/2017/03/ie11hist.png)
```R ```R
hist(firefox$V1, main = "Distribution of Random Values for Firefox", xlab = "Random Value") hist(firefox$V1, main = "Distribution of Random Values for Firefox", xlab = "Random Value")
``` ```
![](/files/images/blog/firefoxhist.png) ![](https://brandonrozek.com/wp-content/uploads/2017/03/firefoxhist.png)
```R ```R
hist(chrome$V1, main = "Distribution of Random Values for Chrome", xlab = "Random Value") hist(chrome$V1, main = "Distribution of Random Values for Chrome", xlab = "Random Value")
``` ```
![](/files/images/blog/chromehist.png) ![](https://brandonrozek.com/wp-content/uploads/2017/03/chromehist.png)
## Chi-Square Test ## Chi-Square Test

View file

@ -46,7 +46,7 @@ The formula for a circle centered at the origin with radius one is $$x^2 + y^2 =
Let us focus again on the first quadrent, and do a Monte Carlo simulation to find the area of the quarter-circle Let us focus again on the first quadrent, and do a Monte Carlo simulation to find the area of the quarter-circle
![](/files/images/blog/circlefilled.png) ![](https://brandonrozek.com/wp-content/uploads/2017/03/circlefilled.png)
We can do this by what is called the dart board method. We generate a random x and y between 0 and 1. If it satisfies the inequality $$x^2 + y^2 \leq 1$$ then it counts as being inside the circle, if not then it lies outside the circle. We can do this by what is called the dart board method. We generate a random x and y between 0 and 1. If it satisfies the inequality $$x^2 + y^2 \leq 1$$ then it counts as being inside the circle, if not then it lies outside the circle.

View file

@ -18,14 +18,13 @@ tags: ["Java"]
--- ---
When you use an IDE there are many things you can take for granted. A section of an intro level computer science course at my university uses [JGrasp](http://www.jgrasp.org/) to build Java Applets. When you use an IDE there are many things you can take for granted. A section of an intro level computer science course at my university uses [JGrasp](http://www.jgrasp.org/) to build Java Applets.
Following around using a normal text editor, I found that I couldn't just compile and run the code like I have with my java programs in the past. To be able to help around and assist in the course, I need to be able to build and run these applications. The rest of this article describes the process I underwent to be able to use my existing setup to write and build java applets. Of course you can always install JGrasp and have that all built in, but it's always nice to not have to change your workflow. Following around using a normal text editor, I found that I couldn&#8217;t just compile and run the code like I have with my java programs in the past. To be able to help around and assist in the course, I need to be able to build and run these applications. The rest of this article describes the process I underwent to be able to use my existing setup to write and build java applets. Of course you can always install JGrasp and have that all built in, but it&#8217;s always nice to not have to change your workflow.
<!--more-->
When I tried following along, I would receive the following error When I tried following along, I would receive the following error
```
Main method not found in class HelloWorld, please define main method as... Main method not found in class HelloWorld, please define main method as...
```
Which makes sense since I have never defined a main method inside my source code. So how do I go about doing this? Which makes sense since I have never defined a main method inside my source code. So how do I go about doing this?
@ -33,20 +32,20 @@ Which makes sense since I have never defined a main method inside my source code
Java Applets are meant to run on web pages, because of this one needs an html file to host the applet. The following code gives you the bare minimum for setting up the html file. I called it `HelloWorld.html`. Java Applets are meant to run on web pages, because of this one needs an html file to host the applet. The following code gives you the bare minimum for setting up the html file. I called it `HelloWorld.html`.
```html <pre class='language-html'><code class='language-html'>
<html>; &lt;html&gt;
<head><title>Applet Container</title> &lt;head&gt;&lt;title&gt;Applet Container&lt;title&gt;
<body> &lt;body&gt;
<applet code='HelloWorld.class' width=400 height=400></applet> &lt;applet code='HelloWorld.class' width=400 height=400&gt;&lt;/applet&gt;
</body> &lt;/body&gt;
</html> &lt;/html&gt;
``` </code></pre>
## Hello World Program ## Hello World Program
To get it up and running, I will show a &#8220;Hello World&#8221; like application for applets. To get it up and running, I will show a &#8220;Hello World&#8221; like application for applets.
```java <pre class='language-java'><code class='language-java'>
import javax.swing.JApplet; import javax.swing.JApplet;
import java.awt.Graphics; import java.awt.Graphics;
@ -55,21 +54,17 @@ public class HelloWorld extends JApplet {
g.drawString("Hello World", 30, 30); g.drawString("Hello World", 30, 30);
} }
} }
``` </code></pre>
## Running the Applet ## Running the Applet
Now we need to compile the code Now we need to compile the code
```bash <pre class='langauge-bash'><code class='language-bash'>javac HelloWorld.java</code></pre>
javac HelloWorld.java
```
Then run the appletviewer Then run the appletviewer
```bash <pre class='language-bash'><code class='language-bash'>appletviewer HelloWorld.html</code></pre>
appletviewer HelloWorld.html
```
## Conclusion ## Conclusion

View file

@ -22,43 +22,41 @@ This post, over time, will serve as a reference to myself and others of the diff
Buttons are created using the JButton component. The constructor takes the text placed inside the button. Buttons are created using the JButton component. The constructor takes the text placed inside the button.
```java <pre class='language-java'><code class='language-java'>
JButton stopBtn = new JButton("Stop"); JButton stopBtn = new JButton("Stop");
``` </code></pre>
![](/files/images/blog/stopbutton.png)
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/stopbutton.png" alt="" width="67" height="25" class="alignnone size-full wp-image-2211" />
You can also add images inside a button. To do that you need to get the image and make it into an icon. The following code grabs the image file &#8220;smallpanda.jpg&#8221; from the current working directory. You can also add images inside a button. To do that you need to get the image and make it into an icon. The following code grabs the image file &#8220;smallpanda.jpg&#8221; from the current working directory.
```java <pre class='langauge-java'><code class='language-java'>
Image img = this.getImage(this.getCodeBase(), "smallpanda.jpg"); Image img = this.getImage(this.getCodeBase(), "smallpanda.jpg");
ImageIcon imgIcon = new ImageIcon(img); ImageIcon imgIcon = new ImageIcon(img);
JButton feedBtn = new JButton("Feed", imgIcon); JButton feedBtn = new JButton("Feed", imgIcon);
``` </code></pre>
Sometimes, you want to change the location of the text in the button. Like say, we want to place the text in the center horizontally and bottom vertically. Sometimes, you want to change the location of the text in the button. Like say, we want to place the text in the center horizontally and bottom vertically.
```java <pre class='language-java'><code class='language-java'>
feedBtn.setHorizontalTextPosition(JButton.CENTER); feedBtn.setHorizontalTextPosition(JButton.CENTER);
feedBtn.setVerticalTextPosition(JButton.BOTTOM); feedBtn.setVerticalTextPosition(JButton.BOTTOM);
``` </code></pre>
Don't forget to add your buttons to the screen! Don&#8217;t forget to add your buttons to the screen!
```java <pre class='language-java'><code class='language-java'>
this.add(stopBtn); this.add(stopBtn);
this.add(feedBtn); this.add(feedBtn);
``` </code></pre>
![](/files/images/blog/smallpandabutton.png)
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/smallpandabutton.png" alt="" width="234" height="181" class="alignnone size-full wp-image-2210" />
### Labels and Textfields ### Labels and Textfields
One of the most common forms of input is a text field, usually distinguished with a label. Those components are called JTextField and JLabel respectively. The constructor for JTextArea can take just the width of the text field, or another common use is to have already inputed text and its width. One of the most common forms of input is a text field, usually distinguished with a label. Those components are called JTextField and JLabel respectively. The constructor for JTextArea can take just the width of the text field, or another common use is to have already inputed text and its width.
```java <pre class='language-java'><code class='language-java'>
JLabel nameLabel = new JLabel("Enter in your name: "); JLabel nameLabel = new JLabel("Enter in your name: ");
// Create an input and set the width to be 10px wide // Create an input and set the width to be 10px wide
@ -69,30 +67,28 @@ One of the most common forms of input is a text field, usually distinguished wit
this.add(nameLabel); this.add(nameLabel);
this.add(nameInput); this.add(nameInput);
``` </code></pre>
![](/files/images/blog/labeltextfield.png)
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/labeltextfield.png" alt="" width="274" height="24" class="alignnone size-full wp-image-2209" />
### Checkboxes ### Checkboxes
Checkboxes are commonly used when giving the possibility for multiple answers. Such as, check all of the foods that you like. Checkboxes are commonly used when giving the possibility for multiple answers. Such as, check all of the foods that you like.
```java <pre class='language-java'><code class='language-java'>
JCheckBox pizza = new JCheckBox("Pizza"); JCheckBox pizza = new JCheckBox("Pizza");
JCheckBox noodles = new JCheckBox("Noodles"); JCheckBox noodles = new JCheckBox("Noodles");
JCheckBox rice = new JCheckBox("Rice"); JCheckBox rice = new JCheckBox("Rice");
this.add(pizza); this.add(pizza);
this.add(noodles); this.add(noodles);
this.add(rice); this.add(rice);
``` </code></pre>
![](/files/images/blog/checkboxes.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/06/checkboxes.png" alt="" width="206" height="40" class="alignnone size-full wp-image-2207" />
You can even replace the default look of the checkbox with an image. To do this, you need to make image icons for both when it&#8217;s checked and when it&#8217;s unchecked.
You can even replace the default look of the checkbox with an image. To do this, you need to make image icons for both when it's checked and when it's unchecked. <pre class='language-java'><code class='language-java'>
```java
Image checkedImage = this.getImage(this.getCodeBase(), "checked.png"); Image checkedImage = this.getImage(this.getCodeBase(), "checked.png");
Image uncheckedImage = this.getImage(this.getCodeBase(), "unchecked.png"); Image uncheckedImage = this.getImage(this.getCodeBase(), "unchecked.png");
@ -103,33 +99,32 @@ JCheckBox checkbox = new JCheckBox("Check Me", uncheckedIcon);
checkbox.setSelectedIcon(checkedIcon); checkbox.setSelectedIcon(checkedIcon);
this.add(checkbox); this.add(checkbox);
``` </code></pre>
![](/files/images/blog/unchecked.png)
![](/files/images/blog/checked.png)
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/unchecked.png" alt="" width="187" height="123" class="alignnone size-full wp-image-2213" />
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/checked.png" alt="" width="186" height="102" class="alignnone size-full wp-image-2208" />
### Text Areas ### Text Areas
Text Areas are different from text fields in which it is made to be able to hold multiple lines of text. It's called JTextArea and its construction takes a width and height as it's arguments. Text Areas are different from text fields in which it is made to be able to hold multiple lines of text. It&#8217;s called JTextArea and its construction takes a width and height as it&#8217;s arguments.
```java <pre class='language-java'><code class='language-java'>
JTextArea textarea = new JTextArea(10, 10); JTextArea textarea = new JTextArea(10, 10);
``` </code></pre>
By default, when the someone inputs more text than the size can hold, it will automatically grow with the text inputted. To override this behaviour and instead introuduce scroll bars. One must define a ScrollPane and put the TextArea inside of it by using it as the scroll pane's argument for its constructor. By default, when the someone inputs more text than the size can hold, it will automatically grow with the text inputted. To override this behaviour and instead introuduce scroll bars. One must define a ScrollPane and put the TextArea inside of it by using it as the scroll pane&#8217;s argument for its constructor.
```java <pre class='language-java'><code class='language-java'>
JScrollPane scrollPane = new JScrollPane(textarea); JScrollPane scrollPane = new JScrollPane(textarea);
``` </code></pre>
![](/files/images/blog/textarea.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/06/textarea.png" alt="" width="119" height="149" class="alignnone size-full wp-image-2212" />
### Radio Buttons ### Radio Buttons
Radio buttons are used for when you only want one out of many different options to be selected. For this, one needs to define a button group that houses the radio buttons for the user to choose from. This can be achieved with ButtonGroup and JRadioButton respectively. Radio buttons are used for when you only want one out of many different options to be selected. For this, one needs to define a button group that houses the radio buttons for the user to choose from. This can be achieved with ButtonGroup and JRadioButton respectively.
```java <pre class='language-java'><code class='language-java'>
// Make the radio buttons // Make the radio buttons
JRadioButton radio1 = new JRadioButton("Pies"); JRadioButton radio1 = new JRadioButton("Pies");
JRadioButton radio2 = new JRadioButton("Cakes"); JRadioButton radio2 = new JRadioButton("Cakes");
@ -145,56 +140,55 @@ desserts.add(radio3);
this.add(radio1); this.add(radio1);
this.add(radio2); this.add(radio2);
this.add(radio3); this.add(radio3);
``` </code></pre>
![](/files/images/blog/radiobuttons.png)
<img src="https://brandonrozek.com/wp-content/uploads/2017/06/radiobuttons.png" alt="" width="211" height="34" class="alignnone size-full wp-image-2218" />
### JList ### JList
To display a list of items that are clickable by the user, you can use a `JList`. JLists require a model that stores the list implementation, we'll use `DefaultListModel` to achieve this purpose. To display a list of items that are clickable by the user, you can use a `JList`. JLists require a model that stores the list implementation, we&#8217;ll use `DefaultListModel` to achieve this purpose.
```java <pre class='language-java'><code class='language-java'>
DefaultListModel model = new DefaultListModel(); DefaultListModel model = new DefaultListModel();
JList list = new JList(model); JList list = new JList(model);
``` </code></pre>
To add scrolling capabilities, remember to add it to a scroll pane To add scrolling capabilities, remember to add it to a scroll pane
```java <pre class='language-java'><code class='language-java'>
JScollPane sp = new JScrollPane(list); JScollPane sp = new JScrollPane(list);
``` </code></pre>
You can set the number of items you wish to see in the list. The example below, allows us to see three items in the list. You can set the number of items you wish to see in the list. The example below, allows us to see three items in the list.
```java <pre class='language-java'><code class='language-java'>
list.setVisibleRowCount(3); list.setVisibleRowCount(3);
``` </code></pre>
There are a variety of ways to add items to the list. If a number is specified that tells it to place it at the index specified. Starting from the top at zero, to the button. There are a variety of ways to add items to the list. If a number is specified that tells it to place it at the index specified. Starting from the top at zero, to the button.
```java <pre class='language-java'><code class='language-java'>
model.addElement("Apples") model.addElement("Apples")
model.addElement("Cherries"); model.addElement("Cherries");
model.addElement("Bananas"); model.addElement("Bananas");
// Adds 'Oranges' to the top // Adds 'Oranges' to the top
model.add(0, "Oranges"); model.add(0, "Oranges");
``` </code></pre>
Sometimes, you want to only let the user select one item. At the end, don't forget to add the component to the screen! Sometimes, you want to only let the user select one item. At the end, don&#8217;t forget to add the component to the screen!
```java <pre class='language-java'><code class='language-java'>
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.add(sp); this.add(sp);
``` </code></pre>
![](/files/images/blog/JList.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/06/JList.png" alt="" width="77" height="53" class="alignnone size-full wp-image-2224" />
### JComboBox ### JComboBox
To create a dropdown list of different options, consider using a JComboBox. To create a dropdown list of different options, consider using a JComboBox.
```java <pre class='language-java'><code class='language-java'>
JComboBox cb = new JComboBox(); JComboBox cb = new JComboBox();
cb.addItem("Select Food Option"); cb.addItem("Select Food Option");
cb.addItem("Pizza"); cb.addItem("Pizza");
@ -203,6 +197,6 @@ cb.addItem("Hot Dog");
cb.addItem("Steak"); cb.addItem("Steak");
// Add it to the screen // Add it to the screen
this.add(cb); this.add(cb);
``` </code></pre>
![](/files/images/blog/JComboBox.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/06/JComboBox.png" alt="" width="153" height="24" class="alignnone size-full wp-image-2223" srcset="https://brandonrozek.com/wp-content/uploads/2017/06/JComboBox.png 153w, https://brandonrozek.com/wp-content/uploads/2017/06/JComboBox-150x24.png 150w" sizes="(max-width: 153px) 100vw, 153px" />

View file

@ -24,12 +24,12 @@ The default theme for Java Swing components is a cross-platform theme called &#8
In the init method of your java application, place the following code. In the init method of your java application, place the following code.
```java <pre class='language-java'><code class='language-java'>
try { try {
UIManager.setLookAndFeel(UIManager UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName()); .getSystemLookAndFeelClassName());
} catch(Exception e) {} } catch(Exception e) {}
``` </code></pre>
Here the application will attempt to look up the system theme and set that as the default styles for the Swing components. If the lookup fails, then it will default back to the metal theme. Here the application will attempt to look up the system theme and set that as the default styles for the Swing components. If the lookup fails, then it will default back to the metal theme.
@ -37,6 +37,6 @@ For more information, check out this page from [Oracle](http://docs.oracle.com/j
### Discussion ### Discussion
If it is so easy to set up applications that look native to each desktop environment, why not have that by default? With the cross platform metal theme, you can ensure that the style of your application is the same across all the operating systems. In this fashion, you don't need to worry about spacing between components and have full control of the &#8220;look and feel&#8221; of your application. If it is so easy to set up applications that look native to each desktop environment, why not have that by default? With the cross platform metal theme, you can ensure that the style of your application is the same across all the operating systems. In this fashion, you don&#8217;t need to worry about spacing between components and have full control of the &#8220;look and feel&#8221; of your application.
Since I am used to development for the web, I don't have strong motivation to have an application look the same on all platforms. I prefer the application to match the system theme and look like it was built for the platform that I am on. One loses partial control on the presentation of your application across different desktop environmnets, but with a strong layout, it is possible to make it look organized and integrated. Since I am used to development for the web, I don&#8217;t have strong motivation to have an application look the same on all platforms. I prefer the application to match the system theme and look like it was built for the platform that I am on. One loses partial control on the presentation of your application across different desktop environmnets, but with a strong layout, it is possible to make it look organized and integrated.

View file

@ -14,7 +14,7 @@ mf2_syndication:
- 'a:1:{i:0;s:60:"https://twitter.com/B_RozekJournal/status/955308388384235521";}' - 'a:1:{i:0;s:60:"https://twitter.com/B_RozekJournal/status/955308388384235521";}'
tags: [] tags: []
--- ---
This article is based on one written by [Markus Konrad](https://datascience.blog.wzb.eu/author/markus_konrad/) at this link [https://datascience.blog.wzb.eu/2016/07/13/autocorrecting-misspelled-words-in-python-using-hunspell/](https://datascience.blog.wzb.eu/2016/07/13/autocorrecting-misspelled-words-in-python-using-hunspell/). This article is based on one written by [Markus Konrad](https://datascience.blog.wzb.eu/author/markus_konrad/) at this link <a href='https://datascience.blog.wzb.eu/2016/07/13/autocorrecting-misspelled-words-in-python-using-hunspell/' target='_blank' >https://datascience.blog.wzb.eu/2016/07/13/autocorrecting-misspelled-words-in-python-using-hunspell/</a>
I assume in this article that you have hunspell and it's integration with python installed. If not, please refer to the article mention above and follow the prerequisite steps. I assume in this article that you have hunspell and it's integration with python installed. If not, please refer to the article mention above and follow the prerequisite steps.
@ -24,10 +24,8 @@ This article is inspired from the need to correct misspelled words in the [Dress
Misspelled words are common when dealing with survey data or data where humans type in the responses manually. In the Dress Attributes Dataset this is apparent when looking at the sleeve lengths of the different dresses. Misspelled words are common when dealing with survey data or data where humans type in the responses manually. In the Dress Attributes Dataset this is apparent when looking at the sleeve lengths of the different dresses.
```python <pre><code class='language-python' lang='python'>dresses_data[&#39;SleeveLength&#39;].value_counts()
dresses_data['SleeveLength'].value_counts() </code></pre><figure>
```
| Word | Frequency | | Word | Frequency |
| -------------- | --------- | | -------------- | --------- |
@ -47,7 +45,7 @@ dresses_data['SleeveLength'].value_counts()
| turndowncollor | 1 | | turndowncollor | 1 |
| sleveless | 1 | | sleveless | 1 |
| butterfly | 1 | | butterfly | 1 |
| threequater | 1 | | threequater | 1 |</figure>
Ouch, so many misspelled words. This is when my brain is racking up all the ways I can automate this problem away. Hence my stumbling upon Markus' post. Ouch, so many misspelled words. This is when my brain is racking up all the ways I can automate this problem away. Hence my stumbling upon Markus' post.
@ -57,22 +55,20 @@ First, I decided to completely ignore what Markus warns in his post and automati
To begin the code, let's import and create an instance of the spellchecker: To begin the code, let's import and create an instance of the spellchecker:
```python <pre><code class='language-python' lang='python'>from hunspell import HunSpell
from hunspell import HunSpell spellchecker = HunSpell(&#39;/usr/share/hunspell/en_US.dic&#39;, &#39;/usr/share/hunspell/en_US.aff&#39;)
spellchecker = HunSpell('/usr/share/hunspell/en_US.dic', '/usr/share/hunspell/en_US.aff') </code></pre>
```
I modified his `correct_words` function so that it only corrects one word and so I can `apply` it along the `SleeveLength` column. I modified his `correct_words` function so that it only corrects one word and so I can `apply` it along the `SleeveLength` column.
```python <pre><code class='language-python' lang='python'>def correct_word(checker, word, add_to_dict=[]):
def correct_word(checker, word, add_to_dict=[]):
"Takes in a hunspell object and a word and corrects the word if needed" "Takes in a hunspell object and a word and corrects the word if needed"
# Add custom words to the dictionary # Add custom words to the dictionary
for w in add_to_dict: for w in add_to_dict:
checker.add(w) checker.add(w)
corrected = "" corrected = ""
# Check to see if it's a string # Check to see if it&#39;s a string
if isinstance(word, str): if isinstance(word, str):
# Check the spelling # Check the spelling
ok = checker.spell(word) ok = checker.spell(word)
@ -93,17 +89,15 @@ def correct_word(checker, word, add_to_dict=[]):
## Not a string. Return original ## Not a string. Return original
corrected = word corrected = word
return corrected return corrected
``` </code></pre>
Now let's apply the function over the `SleeveLength` column of the dataset: Now let's apply the function over the `SleeveLength` column of the dataset:
```python <pre><code class='language-python' lang='python'>dresses_data[&#39;SleeveLength&#39;] = dresses_data[&#39;SleeveLength&#39;].apply(
dresses_data['SleeveLength'] = dresses_data['SleeveLength'].apply( lambda x: correct_word(spellchecker, x))
lambda x: correct_word(spellchecker, x) </code></pre>
)
```
Doing so creates the following series: Doing so creates the following series:<figure>
| Word | Frequency | | Word | Frequency |
| -------------- | --------- | | -------------- | --------- |
@ -120,7 +114,7 @@ Doing so creates the following series:
| turndowncollor | 1 | | turndowncollor | 1 |
| half | 1 | | half | 1 |
| landownership | 1 | | landownership | 1 |
| forequarter | 1 | | forequarter | 1 |</figure>
As you might be able to tell, this process didn't go as intended. `landownership` isn't even a length of a sleeve! As you might be able to tell, this process didn't go as intended. `landownership` isn't even a length of a sleeve!
@ -130,8 +124,7 @@ This is when I have to remember, technology isn't perfect. Instead we should rel
Keeping that in mind, I modified the function again to take in a list of the data, and return a dictionary that has the misspelled words as the keys and suggestions as the values represented as a list. Keeping that in mind, I modified the function again to take in a list of the data, and return a dictionary that has the misspelled words as the keys and suggestions as the values represented as a list.
```python <pre><code class='language-python' lang='python'>def list_word_suggestions(checker, words, echo = True, add_to_dict=[]):
def list_word_suggestions(checker, words, echo = True, add_to_dict=[]):
"Takes in a list of words and returns a dictionary with mispellt words as keys and suggestions as a list. Also prints it out" "Takes in a list of words and returns a dictionary with mispellt words as keys and suggestions as a list. Also prints it out"
# add custom words to the dictionary # add custom words to the dictionary
for w in add_to_dict: for w in add_to_dict:
@ -148,34 +141,31 @@ def list_word_suggestions(checker, words, echo = True, add_to_dict=[]):
elif echo: elif echo:
print(word + ": " + "[", ", ".join(repr(i) for i in suggestions[word]), "]") print(word + ": " + "[", ", ".join(repr(i) for i in suggestions[word]), "]")
return suggestions return suggestions
``` </code></pre>
With that, I can use the function on my data. To do so, I convert the pandas values to a list and pass it to the function: With that, I can use the function on my data. To do so, I convert the pandas values to a list and pass it to the function:
```python <pre><code class='language-python' lang='python'>s = list_word_suggestions(spellchecker, dresses_data[&#39;SleeveLength&#39;].values.tolist())
s = list_word_suggestions(spellchecker, dresses_data['SleeveLength'].values.tolist()) </code></pre>
```
These are the suggestions it produces: These are the suggestions it produces:
``` <pre><code class='language-python' lang='python'>sleevless: [ &#39;sleeveless&#39;, &#39;sleepless&#39;, &#39;sleeves&#39;, &#39;sleekness&#39;, &#39;sleeve&#39;, &#39;lossless&#39; ]
sleevless: [ 'sleeveless', 'sleepless', 'sleeves', 'sleekness', 'sleeve', 'lossless' ] threequarter: [ &#39;three quarter&#39;, &#39;three-quarter&#39;, &#39;forequarter&#39; ]
threequarter: [ 'three quarter', 'three-quarter', 'forequarter' ] halfsleeve: [&#39;half sleeve&#39;, &#39;half-sleeve&#39;, &#39;sleeveless&#39; ]
halfsleeve: ['half sleeve', 'half-sleeve', 'sleeveless' ]
turndowncollor: No suggestions turndowncollor: No suggestions
threequater: [ 'forequarter' ] threequater: [ &#39;forequarter&#39; ]
capsleeves: [ 'cap sleeves', 'cap-sleeves', 'capsules' ] capsleeves: [ &#39;cap sleeves&#39;, &#39;cap-sleeves&#39;, &#39;capsules&#39; ]
sleeevless: [ 'sleeveless', 'sleepless', 'sleeves', 'sleekness', 'sleeve' ] sleeevless: [ &#39;sleeveless&#39;, &#39;sleepless&#39;, &#39;sleeves&#39;, &#39;sleekness&#39;, &#39;sleeve&#39; ]
urndowncollor: [ 'landownership' ] urndowncollor: [ &#39;landownership&#39; ]
thressqatar: [ 'throatiness' ] thressqatar: [ &#39;throatiness&#39; ]
sleveless: [ 'sleeveless', 'levelness', 'valveless', 'loveless', 'sleepless' ] sleveless: [ &#39;sleeveless&#39;, &#39;levelness&#39;, &#39;valveless&#39;, &#39;loveless&#39;, &#39;sleepless&#39; ]
``` </code></pre>
From here, you can analyze the output and do the replacements yourself: From here, you can analyze the output and do the replacements yourself:
```python <pre><code class='language-python' lang='python'>dresses_data[&#39;SleeveLength&#39;].replace(&#39;sleevless&#39;, &#39;sleeveless&#39;, inplace = True)
dresses_data['SleeveLength'].replace('sleevless', 'sleeveless', inplace = True) </code></pre>
```
### What's the Benefit? ### What's the Benefit?

View file

@ -71,9 +71,9 @@ An ideal $J$ of a commutative ring is said to be a **prime ideal** if for any tw
$$ $$
ab \in J \implies a \in J \text{ or } b \in J ab \in J \implies a \in J \text{ or } b \in J
$$ $$
**Theorem:** If $J$ is a prime ideal of a community ring with unity $A$, then the quotient ring $A / J$ is an integral domain. <u>Theorem:</u> If $J$ is a prime ideal of a community ring with unity $A$, then the quotient ring $A / J$ is an integral domain.
An ideal $J$ of $A$ with $J \ne A$ is called a **maximal ideal** if there exists no proper ideal $K$ of $A$ such that $J \subseteq K$ with $J \ne K$. An ideal $J$ of $A$ with $J \ne A$ is called a **maximal ideal** if there exists no proper ideal $K$ of $A$ such that $J \subseteq K$ with $J \ne K$.
**Theorem:** If $A$ is a commutative ring with unity, then $J$ is a maximal ideal of $A$ iff $A/J$ is a field. <u>Theorem:</u> If $A$ is a commutative ring with unity, then $J$ is a maximal ideal of $A$ iff $A/J$ is a field.

View file

@ -1,265 +0,0 @@
---
title: "Adventures in Rust WebAssembly"
date: 2025-02-21T10:13:17-05:00
draft: false
tags: ["Rust", "Web"]
math: false
medium_enabled: false
---
For two years now, my friend and colleague [James Oswald](https://jamesoswald.dev) has told me to check out [WebAssembly](https://webassembly.org/). I avoided it all this time because I thought it would be too complicated to get started with. In one of our study sessions, my friends Chris and Ethan both said they wanted to look into it. I have to say, that getting started with WebAssembly is far simpler than I've previously imagined and it makes me wish I listened to James earlier.
In this post, I'll show how to use Rust + Webassembly to create both a CLI application and a Web application. [The Rust and Webassembly Book](https://rustwasm.github.io/docs/book/) is a great resource, however like [Diego](https://dzfrias.dev/blog/rust-wasm-minimal-setup/), I found the recommended setup to be a bit too heavy for my liking. I'll do anything to avoid using `npm` in personal projects.
### Setup
I assume that you have the [`rustup`](https://www.rust-lang.org/tools/install) command available.
First, we'll need to have the `wasm` toolchains installed.
- For CLI applications: `rustup target add wasm32-wasi`
- For Web applications: `rustup target add wasm32-unknown-unknown`
For the web, we'll also need `wasm-bindgen` to create the JavaScript glue code which ingests the `.wasm` file.
```bash
cargo install wasm-bindgen-cli
```
Now we can create our Rust project!
```bash
cargo new rustwasm
```
This will create the following directory structure
```
rustwasm
├── Cargo.toml
└── src
└── main.rs
```
To compile WebAssembly for the Web, edit the `Cargo.toml` to set the crate-type and add the dependencies.
```toml
[package]
name = "rustwasm"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2.84"
js-sys = "0.3.77"
```
In the following Rust examples, there will be snippets of `wasm_bindgen` scattered about. This is to create the JavaScript glue code. If you're only running on the CLI then those lines are not needed, but it doesn't hurt to include them.
Let's add a greeter function that returns the string `"Hello World"` in `src/lib.rs`
```rust
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn greeting() -> String {
return String::from("Hello World");
}
```
### CLI Application
For our CLI application, we'll create a `main` function that calls our new `greeting` function. This will live in `src/main.rs`
```rust
use rustwasm;
fn main() {
let _args = std::env::args();
println!("{}", rustwasm::greeting());
}
```
I include the `_args` variable to show how you would obtain the command-line arguments, however we won't do anything with those in this example.
To run this in the CLI, we first need to compile the `wasm` file.
```bash
cargo build --target wasm32-wasi --release
```
Then we can use [`wasmtime`](https://wasmtime.dev/) to execute the file
```bash
wasmtime target/wasm32-wasi/release/rustwasm.wasm
```
Feel free to distribute `rustwasm.wasm` among your friends to run on their machines as well!
### Web application
Now let's show how we would run this in the web! First let's create a `public` folder at the base of the Rust project which we'll use to host the website code.
```bash
mkdir public
```
Within `public/index.html` include the following:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm!</title>
</head>
<body>
<script type="module" src="index.js"></script>
</body>
</html>
```
*Note the `type="module"` within the script tag.*
The JavaScript code we have to write luckily is minimal since `rust-bindgen` does the majority of the work for us. Note that we're not running the`main` function within `main.rs`. Instead, we only have access to the methods, structs, etc that are public and annotated with `#[rust_bindgen]` beforehand.
Recall in `lib.rs` that we have the `greeting` function. We would incorporate that into our web application through the following code within `public/index.js`
```javascript
import init, * as wasm from "./rustwasm.js";
await init();
console.log(wasm.greeting());
```
Now, we need to compile our codebase and use `wasm-bindgen` to generate the glue code.
```bash
cargo build --target wasm32-unknown-unknown --release
wasm-bindgen target/wasm32-unknown-unknown/release/rustwasm.wasm --out-dir public --target web
```
*Note: Everytime you update your Rust code, you'll need to run both those commands*
To test this, we can quickly spin up a Python web server.
```bash
cd public
python -m http.server
```
By default your web application would be served at https://localhost:8000. If you open up your console and refresh, you should see the `"Hello World"` message printed.
## More Web Examples
Through the magic of `wasm-bindgen`, we were able to create a function in Rust that returns a string, and without having to think about the internals of Webassembly, get a JavaScript string on the other side.
The primary usecase of WebAssembly in my mind, is to offload heavier computations. You can edit the DOM directly using the [`web-sys`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/) crate. However, I'll focus my remaining examples and getting data in and out of the compiled Rust code.
**Example:** Calling a Rust-wasm function with a primitive argument
Let's create a small Rust function that takes an integer and outputs the integer plus one.
```rust
#[wasm_bindgen]
pub fn plusone(x: i32) -> i32 {
x + 1
}
```
Remember to mark the function as public (`pub`) and annotate it with `#[wasm_bindgen]` in order for it to be available in the JavaScript.
Recompile the Rust code using the two commands from earlier, and edit the `public/index.js` function to log an example output of the function.
```javascript
console.log(wasm.plusone(5))
```
Be careful with what primitive types we use in Rust. If you were to change `i32` to `u32` and call the function in JavaScript with a negative number, then the Rust Wasm side will reinterpret the negative number as a large `u32`.
**Example:** Taking in arbitrary JavaScript values (Dictionaries, arrays, etc.)
Using the [`js-sys`](https://rustwasm.github.io/wasm-bindgen/api/js_sys/index.html) crate, we can take an arbitrary JavaScript value as a parameter and use the `Reflect` module to access field names or interpret the data.
```rust
#[wasm_bindgen]
pub fn get_name(obj: JsValue) -> String {
let key = JsValue::from_str("name");
let value_option = js_sys::Reflect::get(&obj, &key)
.ok()
.and_then(|v| v.as_string());
value_option.unwrap_or_else(|| String::from("Error encountered"))
}
```
In the example above, we take a JavaScript value called `obj` and attempt to access the `name` field as a string. Since `obj` can be any arbitrary JavaScript value, we need to include error handling within our code. There are three possible error conditions:
- `obj` is not a JavaScript object (within `js_sys::Reflect::get`)
- `"name"` is not a field in the object (also within `js_sys::Reflect::get`)
- `obj.name` is not a string (within `.as_string()`)
It's a little burdensome to write this code. But given that JavaScript isn't a typed language, it's amazing we can process arbitrary JavaScript values at all.
**Example:** Returning a `struct` from Rust-wasm
Say we have a `Person` struct.
```rust
#[wasm_bindgen]
pub struct Person {
name: String,
age: u32,
}
```
In order for this struct to be accessible in the JavaScript, we'll need to make it public (`pub`) and add the `#[wasm_bindgen]` annotation.
Additionally, JavaScript objects have constructors and getter functions. We'll need to implement those publicly within Rust and add the right annotations.
```rust
#[wasm_bindgen]
impl Person {
#[wasm_bindgen(constructor)]
pub fn new(name: String, age: u32) -> Person {
Person { name, age }
}
// Getter for name field
pub fn name(&self) -> String {
self.name.clone()
}
// Getter for the age field
pub fn age(&self) -> u32 {
self.age
}
}
```
Lastly, let's create a small function that returns a specific `Person` struct.
```rust
#[wasm_bindgen]
pub fn bob() -> Person {
return Person::new(String::from("Bob"), 22)
}
```
Now within `public/index.js`, we can call `wasm.bob()` and bring over the new person object. From there, we can access its fields using the getter methods.
```javascript
const person = wasm.bob();
console.log("Name: " + person.name() + ", Age: " + person.age);
```
That's all for today! From here the world is our oyster. We can leverage the type safe and efficient properties of Rust and write code that's not only available on the Web, but also through the CLI; all while being architecture-independent.

View file

@ -76,28 +76,28 @@ coefficients of CUST2 and the y-intercept.
##### Checking the Conditions for Inference ##### Checking the Conditions for Inference
Before we conclude with the analysis, we must first check the conditions for inference to see if the technique is appropriate for our data. Before we conclude with the analysis, we must first check the conditions for inference to see if the technique is appropriate for our data.
**Independence Assumption:** <u>Independence Assumption:</u>
A houses selling price can depend on anothers so this condition is not met. A houses selling price can depend on anothers so this condition is not met.
**Randomization Condition:** <u>Randomization Condition:</u>
The dataset is comprised of a random sample of records of resale of homes which satisfies the The dataset is comprised of a random sample of records of resale of homes which satisfies the
randomization condition. randomization condition.
**Straight Enough Condition:** <u>Straight Enough Condition:</u>
The scatterplot matrix in Figure 20 shows that for the predictors square footage and tax that the The scatterplot matrix in Figure 20 shows that for the predictors square footage and tax that the
scatterplot is straight enough and doesnt have any bends or curves. scatterplot is straight enough and doesnt have any bends or curves.
**Equal Variance Assumption:** <u>Equal Variance Assumption:</u>
The residual analysis in Figure 21 shows that the outliers are not spread equally on the The residual analysis in Figure 21 shows that the outliers are not spread equally on the
scatterplot. Therefore, the equal variance assumption is not met. scatterplot. Therefore, the equal variance assumption is not met.
**Nearly Normal Condition:** <u>Nearly Normal Condition:</u>
The QQ-Plot in Figure 21 shows that the residuals follow a unimodal and symmetric distribution. The QQ-Plot in Figure 21 shows that the residuals follow a unimodal and symmetric distribution.
Taking out the outliers in the model also did not introduce any new outliers in the boxplot. Taking out the outliers in the model also did not introduce any new outliers in the boxplot.
**Missing At Random Condition:** <u>Missing At Random Condition:</u>
7The discussion in the descriptive statistics section about the missing data tells us that the data 7The discussion in the descriptive statistics section about the missing data tells us that the data
is missing evenly with respect to the different variables. Therefore, it is safe to assume that the is missing evenly with respect to the different variables. Therefore, it is safe to assume that the
data is missing at random data is missing at random
**Multicollinearity Condition:** <u>Multicollinearity Condition:</u>
All of the VIF values are lower than 10, therefore this condition is met. All of the VIF values are lower than 10, therefore this condition is met.
The conditions for inference are not fully met due to the equal variance assumption. This means that our model will be more inaccurate for some price range of homes than others. Looking at our residual analysis, it appears that the inaccuracies happen when the price of the home is higher. There werent many outliers in the dataset (6 out of 117 or 5%) so removing these outliers makes the model more representative to the majority of the houses in the market. Since this model is intended to be used when analyzing prices of homes in the area, it is better not to include the outliers that most people don't intend to buy. Since the error term is unimodal and symmetric, we can be at ease that there isnt any other confounding factor in our model. Overall, this is a good model to use for inference and prediction as long as one doesnt use it to describe the outliers. The conditions for inference are not fully met due to the equal variance assumption. This means that our model will be more inaccurate for some price range of homes than others. Looking at our residual analysis, it appears that the inaccuracies happen when the price of the home is higher. There werent many outliers in the dataset (6 out of 117 or 5%) so removing these outliers makes the model more representative to the majority of the houses in the market. Since this model is intended to be used when analyzing prices of homes in the area, it is better not to include the outliers that most people don&#8217;t intend to buy. Since the error term is unimodal and symmetric, we can be at ease that there isnt any other confounding factor in our model. Overall, this is a good model to use for inference and prediction as long as one doesnt use it to describe the outliers.
### Conclusion ### Conclusion

View file

@ -1,103 +0,0 @@
---
title: "Dealing with Web Scrapers"
date: 2025-07-02T09:10:23-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
Nowadays it seems like every tech company is eager to scrape the web. Unfortunately, it seems like
[^1] the majority of traffic that comes to this small site are scrapers. While my static website is able to handle the load, the same cannot be said about everyone.
[^1]: At least I don't think a human using Chrome would try to visit my homepage every minute.
Overall, the techinques I've seen website owners use aim to make scraping more difficult. Though it's a balance. The harder we make it for bots to access a website, the more we turn away regular humans as well. Here's a short and non-exhaustive list of techinques:
1. User Agent Filtering
2. CAPTCHA solving
3. Rate Limiting
4. Proof of work
5. Identification
6. Paywall
### User Agent Filtering
When a person/bot requests a page from a website, the HTTP header of the request has a field called `User-Agent`. This is to denote the type of client that the requester is using. For example, when I visited a website just now, I sent the user agent `Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0`.
Filtering based on this string is the easiest technique to employ and also has a low chance of impacting regular humans visiting the website. [RFC 9309 Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309.html), more commonly known as `robots.txt`, is the most common way of implementing this technique.
How it works is that you create a file named `robots.txt` at the root directory of your website and write a set of rules that different robots *should* follow. Here's an example from [Google's search documentation](https://developers.google.com/search/docs/crawling-indexing/robots/create-robots-txt):
```txt
User-agent: Googlebot
Disallow: /nogooglebot/
User-agent: *
Allow: /
Sitemap: https://www.example.com/sitemap.xml
```
The `*` here is the Klenne star which means that it can match any string. Before the bot requests a page, the idea is that they first request this `robots.txt` file, find the rules that match their user agent, and follow it's instructions.
As you might imagine, not everyone writes scrapers that follow these rules. This depends on how well-written the bot was and how considerate the developer is. An alternative to this approach is to block the request at the web server. For example, here's how you would do that using `nginx`
```nginx
if ($http_user_agent = "Googlebot"){
return 403;
}
```
This returns an empty response with the HTTP code `403 Forbidden`.
The downside to this approach is that it's easy to pretend that you have a different user agent. For example on my machine, the user agent set by `curl` is `curl/8.9.1`. However, I can use the same user agent as my browser by adding a flag:
```bash
curl --user-agent "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0" https://brandonrozek.com
```
### CAPTCHA Solving
The Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA) is a challenge-response approach to dealing with bots. The idea is that the webserver would present some sort of challenge that is supposedly hard for computers to solve but easy for humans. The human responds to the challenge and then is granted access to the website.
In the paper "Recent advances of Captcha security analysis: a short literature review" by Nghia Trong Dinh and Vinh Truong Hoang, they show that for the majority of CAPTCHA systems, bots are successful at solving them over 50% of the time. Specifically, the best bots are able to solve Google's image-based CAPTCHAs with 70.78% accuracy.
Unfortunately[^2] the success rate of bots are bound to improve over time. Additionally, CAPTCHA systems are annoying to humans. For example, when I use a VPN, I don't bother with Google search since I don't want to select pictures of stairs, fire hydrants, or crosswalks 10 times before being granted a search query.
[^2]: Or fortunately, if we want to get closer to AGI
### Rate Limiting
Computers are inherently faster than us. In the paper "How many words do we read per minute? A review and meta-analysis of reading rate" by Marc Brysbaert, he writes that the average human adult reads 238 words per minute of non-fiction silently. Thus, it would take a human on average almost 11 hours to read all my prior blog posts (assuming they don't get tired or distracted). Meanwhile a bot can scrape this site in under a minute.
From this insight, one technique is to limit the number of requests that an IP address can make at any given time. This is formally known as *rate limiting*.
It sounds simple in concept but can be difficult to implement without impacting user experience. How many requests is a human reasonably allowed to make in a minute? Human traffic is typically bursty, where a page load can request many different files (CSS, JS, media) in a short period of time. How quick can I expect someone to reasonably click around my website? If this isn't dialed in properly, then rate limiting can cause frustration with your visitors.
I'm also unsure how successful this is against the LLM web scrapers. Nowadays there are bot farms where they each have their own IP address. It's difficult to determine whether a request is from a human visitor or part of a larger bot collection network.
### Proof of work
We talked about how CAPTCHAs are difficult for computers but easy for humans. Proof of work is difficult for both computers and humans. This helps reduce the number of scrapers by making it *costly* to request resources from the website. By making the web browser solve some proof of work challenge (usually involving hash functions), the request consumes additional CPU cycles and takes additional time.
Similar to rate limiting, how *difficult* you make the problem has a direct impact on user experience. The more difficult, the longer it'll take for the web browser to solve it. This will deter more bots, but after a few seconds will also deter human visitors. [According to a study performed by Google and SOASTA Research in 2017](https://web.archive.org/web/20250121155519/https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/page-load-time-statistics/), if a user has to wait 3 seconds instead of 1 second, then the probability that they *bounce* (leave the page) increases by 32%.
Recently, open-source projects [Anubis](https://anubis.techaro.lol/) and [go-away](https://git.gammaspectra.live/git/go-away) gained popularity for making it easy to implement this technique. It's popular for git forges like [sourcehut's](https://git.sr.ht/) as scraping those incurs a lot of CPU cycles in traversing git repositories.
### Identification
Another tactic is to ask the requester to provide some information that a human would likely have but a bot less so. Examples include email addresses, phone number, government ID, etc. Of course, a bot can supply false information, but as with the other techinques this adds an additional barrier. Watch out for the [fake phone numbers](https://gregoryhammond.ca/blog/never-to-connect-phone-numbers-a-project/).
### Paywall
Lastly, you can require users to pay to see the contents of your website. This is popular with news organizations where they ask you to pay for a subscription in order to see content. This ties in well with the previous tactic, because if the user pays for a subscription, then you likely have a lot of identifying information about that user.
Another interesting idea that I haven't seen widely implemented is requiring some amount of money per interaction. This can be in the form of the [Web Monetization API](https://webmonetization.org/) or via cryptocurrency like Bitcoin on the [Lightning network](https://lightning.network/). [Stacker news](https://stacker.news/) is an example of a Reddit-like platform where users need to pay a small fee in order to upvote a post. The idea is to make it cheap for a human to do on a small scale (like 1 cent per up-vote), but expensive for a bot to do at scale.
### Conclusion
We're in a special time period where everyone is fighting to become the top AI company. Long term, I feel that the scraper activity will die down. Similar to how there weren't as many web search scrapers out there.
In the meantime, these are multiple techniques to consider if your website is suffering under heavy load. As for myself, I don't currently implement any of these as my website is mostly static and I haven't noticed my servers being overloaded.
However if you do, I urge you to exercise some caution. For the most part, we share on the web for information to flow freely, and if we're not careful we may drive people away.

View file

@ -8,7 +8,7 @@ tags:
title: Autostart Desktop Applications title: Autostart Desktop Applications
--- ---
The [freedesktop specification](https://web.archive.org/web/20240105053937/https://specifications.freedesktop.org/autostart-spec/0.5/ar01s02.html) describes how to identify file types, launch applications, and other useful desktop functions. A useful spec I've found recently is for launching desktop applications when you log into your machine. The [freedesktop specification](https://specifications.freedesktop.org/autostart-spec/0.5/ar01s02.html) describes how to identify file types, launch applications, and other useful desktop functions. A useful spec I've found recently is for launching desktop applications when you log into your machine.
In my Kubuntu 20.10 system, the directory `$HOME/.config/autostart` can contain [`.desktop`](/blog/linuxdesktopicons/) files that describes the applications to start on login. Drop whichever desktop file you wish to start there. In other systems it may be located under `$XDG_CONFIG_DIRS/autostart`. In my Kubuntu 20.10 system, the directory `$HOME/.config/autostart` can contain [`.desktop`](/blog/linuxdesktopicons/) files that describes the applications to start on login. Drop whichever desktop file you wish to start there. In other systems it may be located under `$XDG_CONFIG_DIRS/autostart`.

View file

@ -1,82 +0,0 @@
---
title: "Blog Question Challenge (Jan 2025)"
date: 2025-01-29T21:18:03-05:00
draft: false
tags: []
math: false
medium_enabled: false
---
Catching up on my RSS feeds, [Ava's bear blog question challenge](https://blog.avas.space/bear-blog-challenge/) has been making the rounds. The last blogging trend I remember going viral was [App Defaults](https://defaults.rknight.me/) inspired by an episode of [Hemispheric Views](https://listen.hemisphericviews.com/097) back in November 2023. I felt too awkward last time around to take part, and I wouldn't have said anything this time either, except that I got tagged by [Mark Pitblado](https://www.markpitblado.me/blog/blog-question-challenge-2025).
Nothing makes you feel more cool on the Internet than getting tagged to participate.
## Why did you start blogging?
In the sappiest way possible, I'm not sure where I would be in life if the Internet didn't exist. It's really the generosity of people that share the things they've learned and the life they've lived, that helps guide me through mine.
For this reason, blogging for me has originally served two purposes:
1. To give back to the community by sharing what I've learned;
2. To serve as a second-brain for myself, lest I forget.
As time progresses, I've been slowly exploring blogging from a more social context. A recent addition to my website is `/postroll`, where I give shout-outs to [blog posts I've enjoyed](https://brandonrozek.com/postroll/). Previously, I've written a couple [reply](blog/on-earbuds/) [posts](/blog/re-static-plus/), and I'm less shy on reaching out to fellow bloggers over email.
To the last point, I'm always ecstatic when a reader reaches out to me. [That could be you!](https://brandonrozek.com/contact/)
## What platforms are you using for your blog, and why?
I currently use the static site generator [Hugo](https://gohugo.io/) which takes my blog posts written in Markdown, and presents this great HTML that you're reading right now!
My website files are hosted on two servers. One in New York City hosted by [EasyVM](https://easyvm.net/) and another in Singapore hosted by [GreenCloud](https://greencloudvps.com/). The server you're talking to right now is hopefully the one closest to you. Check out my [GeoDNS post](/blog/implementing-cdn-geodns/) to learn more.
For all I know though, you dear reader are from the distant unforeseeable future. If so, hello! I can't guarantee that anything from this section is correct anymore. This website may be *quantum powered* instead.
## Have you blogged on other platforms before?
In what feels like an eternity ago, my blog used to run on a self-hosted version of Wordpress. Unfortunately, the server provider I was with has faded from my memory. Exactly when the switch occurred is lost to the sands of time as well. According to the [Internet Archive](https://web.archive.org/web/20190901000000*/brandonrozek.com), I started using Hugo sometime between April to July 2019.[^1]
[^1]: Makes me wish I wrote one of those "I switched my website to Hugo!" blog posts
On a separate note, even though I don't actively use them myself, I'm a huge fan of [tildespaces](/blog/tildeverse/). I first discovered them during my undergraduate days, and unfortunately that page has since been taken down. Nowadays, I currently have one at my [graduate institution](https://www.cs.rpi.edu/~rozekb) and you can also find me on [Tilde Club](https://tilde.club/~brozek/).
## How do you write your posts?
Since I write my posts in Markdown, I open up [Typora](https://typora.io/) and button smash until the words stop coming out. I use `hugo serve` to check that the page renders fine, and then I commit the Markdown file to my website's [GitHub repository](https://github.com/brandon-rozek/website). From there, some [automation](/blog/deploying-hugo-website-through-gh-actions/) kicks off which rebuilds my website.
I like to tell myself that I [lint my blog posts](/blog/vale-linter-human-prose/), but let's be real. Who likes having their computer tell them they're wrong? Most of the time these posts escape that extra scrutiny.
## When do you feel most inspired to write?
Usually after I've learned or done something cool. Honestly, there's a slight pressure for me to keep trying new things, since the reward is that I can create a shiny new blog post. I'm far from consistent with writing. I passively collect ideas I want to play around with, and then spend an evening going through my backlog. This results in my publishing happening in bursts.
## Do you normally publish immediately after writing, or do you let it simmer a bit?
In an effort to get posts out of the door, I rarely spend over one session in drafting them. I let these drafts rest a day and give them a quick proof-read when my mind is clear. Since I go through my backlog in batches, I try to keep myself to a one-post-a-day rule. I personally don't like receiving a bunch of updates all at once, so I try my best to not subject my readers to that.
This post happens to be an exception! I created this over *two* whole sessions.
## What's your favorite post on your blog?
Writing for many years now, I won't say that I have an absolute favorite. If forced to pick from 2024, I would probably say my post on [Ice Hockey](/blog/ice-hockey/). It gives a little taste of my personal life while also cataloging what I've learn so far about the sport. My favorite technical deep-dive post of 2024 has to be [Constraints and Safety in PDDL](https://brandonrozek.com/blog/safety-constraints-pddl/).
## Any future plans for the blog?
My blog is coming up on its 10-year anniversary this April which is mind-boggling to me. The vast majority of my posts are technical pieces, and some are [opinion](/blog/paying-for-things/) [pieces](/blog/ai-fearmongering-regulatory-moat/), and [travel](/blog/day-in-brooklyn/) [logs](/blog/circling-around-vancouver/). Thinking about it now, I want to add two other types of pieces to my repertoire:
**Retrospectives:** With the blog anniversary coming up, I'm thinking about looking at some older pieces and see how my perspective has changed over time. I'm also open to talking more about my life in general.
**State of TOPIC:** Back in 2019, what services did I run on my homelab? Unfortunately, I can't recall! With all the technical posts, we can likely infer that I ran a service that I talked about. However, it would be much simpler and likely more useful to people if I cataloged everything that I'm doing at a particcular moment for TOPIC. Currently thinking of my website and homelab.
## Who will participate next?
I tag [Ethan Martin](https://emar10.dev/), [Zak](https://html-chunder.neocities.org/), and [bacardi55](https://bacardi55.io/). Hopefully you'll take part, and if you do, I'll link your response below.
**Update**:
- [bacardi55's response](https://bacardi55.io/2025/01/31/blog-question-challenge-jan-2025/)
- [Zak's response](https://html-chunder.neocities.org/blog/blogging/)
- [Ethan's response](https://emar10.dev/posts/blog-question-challenge-jan2025/)

View file

@ -25,7 +25,7 @@ From my `subscriptions.xml` here's an example entry:
<outline text="Jake Bauer" title="Jake Bauer" type="rss" xmlUrl="https://www.paritybit.ca/feed.xml" htmlUrl="https://www.paritybit.ca/"/> <outline text="Jake Bauer" title="Jake Bauer" type="rss" xmlUrl="https://www.paritybit.ca/feed.xml" htmlUrl="https://www.paritybit.ca/"/>
``` ```
It looks like I need to extract the `title`, `xmlUrl`, and `htmlUrl` attributes in that specific order. I'll use the same technique from a previous post on [capturing quoated strings](/blog/capturing-quoted-string-sed). It looks like I need to extract the `title`, `xmlUrl`, and `htmlUrl` attributes in that specific order. I'll use the same technique from a previous post on [capturing quoated strings](/capturing-quoted-string-sed).
```bash ```bash
grep "xmlUrl" subscriptions.xml |\ grep "xmlUrl" subscriptions.xml |\

View file

@ -1,101 +0,0 @@
---
title: "Curl-able Business Cards"
date: 2024-12-26T09:12:58-05:00
draft: false
tags: []
math: false
medium_enabled: false
---
Browsing around on the Interwebs, I found that [Rahul](https://codingotaku.com/) has a curl card.
```bash
curl https://codingotaku.com/cc
```
```
╔═══════════════════════════════════════════════════════════╗
║ ) ║
║ ( ( ( /( ) ) ║
║ )\ )\ ) ( ( ( )\()) ( /( ) ( /( ( ║
║ (((_) ( (()/( )\ ( )\))( ((_)\ )\()( /( )\()) ))\ ║
║ )\___ )\ ((_)((_) )\ )((_))\ ((_)(_))/)(_)((_)\ /((_)║
║((/ __|((_) _| | (_)_(_/( (()(_) / _ \| |_((_)_| |(_(_))( ║
║ | (__/ _ / _` | | | ' \)/ _` | | (_) | _/ _` | / /| || |║
║ \___\___\__,_| |_|_||_|\__, | \___/ \__\__,_|_\_\ \_,_|║
║ |___/ ║
║ ║
║ -~= free-software = web = anime =~- ║
║ ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ ■ Web developer who adore Minimalism ■ ║
║ ║
║ Email: contact<at>codingotaku<dot>com ║
║ ║
║ Web: https://codingotaku.com/ ║
║ ║
║ Peertube: https://videos.codingotaku.com/c/codingotaku ║
║ Mastodon: https://fosstodon.org/@codingotaku
║ Codeberg: https://codeberg.org/codingotaku ║
║ ║
║ Card: curl -sL https://codingotaku.com/cc ║
║ ║
╚═══════════════════════════════════════════════════════════╝
```
The black and white rendition here really does not give it justice. Run the command yourself so you can see the wicked colors they use.
Now if you ask me, this is really awesome and I need to have this for myself. Searching around, I found an old [GitHub repo](https://github.com/tallguyjenks/BusinessCard) by Bryan Jenks containing the bash script they use to generate their curl card.
```bash
curl https://raw.githubusercontent.com/tallguyjenks/BusinessCard/refs/heads/master/business_card
```
```
╭───────────────────────────────────────────────────────╮
│ │
│ Bryan Jenks / TallGuyJenks │
│ │
│ Email: bryanjenks@protonmail.com │
│ Web: https://www.bryanjenks.dev │
│ │
│ Twitter: https://twitter.com/tallguyjenks │
│ GitHub: https://github.com/tallguyjenks │
│ LinkedIn: https://linkedin.com/in/bryanjenks │
│ YouTube: https://www.youtube.com/c/BryanJenksTech │
│ OrcID: https://orcid.org/0000-0002-9604-3069 │
│ Patreon: https://www.patreon.com/bryanjenks │
│ │
│ Card: curl -sL bit.ly/2AtVaXR │
│ │
╰───────────────────────────────────────────────────────╯
```
Their bash script makes uses of `tput` from the `ncurses` library to set the terminal colors. Adapting their script to include my information, and I now have a curl card of my own!
```bash
curl https://brandonrozek.com/cc
```
```
╭──────────────────────────────────────────────────╮
│ │
│ Brandon Rozek │
│ │
│ Email: brozek@brandonrozek.com │
│ Web: https://brandonrozek.com │
│ │
│ Mastodon: https://fosstodon.org/@brozek
│ GitHub: https://github.com/Brandon-Rozek │
│ │
│ Card: curl -sL brandonrozek.com/cc │
│ │
╰──────────────────────────────────────────────────╯
```

View file

@ -69,7 +69,7 @@ location /.well-known/openpgpkey {
Now we can check our setup using the website: Now we can check our setup using the website:
https://WebKeyDirectory.com https://metacode.biz/openpgp/web-key-directory
## Using WKD ## Using WKD

View file

@ -1,442 +0,0 @@
---
title: "Deterministically Iterating over a set within Dafny functions"
date: 2025-07-06T12:27:01-04:00
draft: false
tags: ["Formal Methods"]
math: false
medium_enabled: false
---
Say we have a set that we want to iterate over within a pure Dafny function. For sake of example, we will look at a set of strings. In Dafny, `var x :| condition` denotes "let us define variable x such that \[condition\]". Therefore, a first attempt at writing our function might be:
```
function iterate_helper(collection: set<string>, acc: seq<string>): seq<string>
{
if collection == {} then acc
else
var x :| x in collection;
var newAcc := acc + [x];
var newCollection := collection - {x};
iterate_helper(newCollection, newAcc)
}
```
The issue is that Dafny will complain with the following error message:
> to be compilable, the value of a let-such-that expression must be uniquely determined
Dafny functions must be deterministic. This means that no matter how many times we call a function with some specified input, we will always get the same output. Therefore, as the error message suggests, we need to write a condition that *uniquely* determines `x`. One way to achieve this is to specify an order as described in [Rustan's paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/12/krml252.pdf):
```
function iterate_helper(collection: set<string>, acc: seq<string>): seq<string>
{
if collection == {} then acc
else
var x :| x in collection && forall y | y in collection :: x <= y;
var newAcc := acc + [x];
var newCollection := collection - {x};
iterate_helper(newCollection, newAcc)
}
````
Unfortunately, this code will return two errors:
> cannot establish the existence of LHS values that satisfy the such-that predicate
> to be compilable, the value of a let-such-that expression must be uniquely determined
However, it's totally possible to define an ordering over strings. We'll just need to do some work to convince the verifier of this.
### Comparing two strings
Since strings in Dafny are a sequence of characters, it turns out that the `<=` relation checks whether the left side is a prefix of the right side. Therefore, there is no such thing as a *unique* minimum element, since there are incomparable elements like "a" and "b".
As such, our first step is to create a less than or equal to (`<=`) relation that induces a total order. Consider the following function that determines the order based on the left-most character.
```function string_le(s1: string, s2: string): bool
function string_le(s1: string, s2: string): bool
decreases |s1| + |s2|
{
if |s1| == 0 && |s2| > 0 then
true
else if |s1| > 0 && |s2| == 0 then
false
else if |s1| == 0 && |s2| == 0 then
true
else
assert(|s1| > 0);
assert(|s2| > 0);
var c1 := s1[0];
var c2 := s2[0];
if c1 < c2 then
true
else if c1 > c2 then
false
else
string_le(s1[1..], s2[1..])
}
```
### Properties of our comparison function
From here we need to prove that our relation induces a total order. For this, we need to show that it is reflexive, total, anti-symmetric, and transitive.
Reflexivity: All strings are less than or equal to themselves
```
lemma string_le_reflexive()
ensures forall s :: string_le(s ,s)
{
forall s ensures string_le(s, s)
{
string_le_reflexive_helper(s);
}
}
lemma string_le_reflexive_helper(s1: string)
ensures string_le(s1, s1)
{}
```
Totality: Given two strings, one is less than or equal to the other.
```
lemma string_le_totality()
ensures forall s1, s2 :: string_le(s1, s2) || string_le(s2, s1)
{
forall s1, s2 ensures string_le(s1, s2) || string_le(s2, s1)
{
string_le_totality_helper(s1, s2);
}
}
lemma string_le_totality_helper(s1: string, s2: string)
ensures string_le(s1, s2) || string_le(s2, s1)
{}
```
Antisymmetric: If one string is less than or equal to another string and that other string is also less than or equal to the original string then both strings are equivalent.
```
lemma string_le_antisymmetric()
ensures forall s1, s2 :: string_le(s1, s2) && string_le(s2, s1) ==> s1 == s2
{
forall s1, s2 | string_le(s1, s2) && string_le(s2, s1)
ensures s1 == s2
{
string_le_antisymmetric_helper(s1, s2);
}
}
lemma string_le_antisymmetric_helper(s1: string, s2: string)
requires string_le(s1, s2)
requires string_le(s2, s1)
ensures s1 == s2
{}
```
Transitive: If one string is less than or equal to another string, and that other string is less than or equal to some third string, then the first string is less than or equal to that third string.
```
lemma string_le_transitive()
ensures forall s1, s2, s3 :: string_le(s1, s2) && string_le(s2, s3) ==> string_le(s1, s3)
{
forall s1, s2, s3 | string_le(s1, s2) && string_le(s2, s3)
ensures string_le(s1, s3)
{
string_le_transitive_helper(s1, s2, s3);
}
}
lemma string_le_transitive_helper(s1: string, s2: string, s3: string)
requires string_le(s1, s2)
requires string_le(s2, s3)
ensures string_le(s1, s3)
{}
```
Then, we conviniently package all the properties together:
```
lemma string_le_properties()
ensures forall s :: string_le(s, s)
ensures forall s1, s2 :: string_le(s1, s2) && string_le(s2, s1) ==> s1 == s2
ensures forall s1, s2, s3 :: string_le(s1, s2) && string_le(s2, s3) ==> string_le(s1, s3)
ensures forall s1, s2 :: string_le(s1, s2) || string_le(s2, s1)
{
string_le_reflexive();
string_le_antisymmetric();
string_le_transitive();
string_le_totality();
}
```
### String sets have a minimum
With the total ordering of strings, we can prove that a smallest element exists within a non-empty set `s`. First, let us invoke our comparison properties lemma, so the verifier has access to those properties:
```
string_le_properties();
```
Since our set is non-empty, we can grab an arbitrary element from `s`.
```
var x :| x in s;
```
For this proof, we'll approach it inductively. First, let's consider when `s == {x}`.
1. By construction, every element in `s` is equal to `x`.
2. Then by reflexivity, `x` is smaller than every element in `s`.
```
assert forall y :: y in s ==> y == x;
assert forall y :: y in s ==> string_le(x, y);
```
Now let's consider the inductive case. The set in this case has more elements than just `x`. Let's consider `s'` the subset of `s` without the element `x`.
```
var s' := s - {x};
assert s' != {};
```
Since `s'` is non-empty, we can by induction say that `s'` has a smallest element.
```
string_smallest_exists(s');
var x' :| x' in s' && forall y :: y in s' ==> string_le(x', y);
```
As `s'` is the subset of `s` without `x`, we can assert that `x'` and `x` are not the same:
```
assert x' != x;
```
From here, we compare both `x` and `x'` (which we're able to do since `<=` is total)
Case 1: `x <= x'`: By transitivity, `x` will be less than all the elements of `s'`. Since `s'` is `s` without `x`, we can safely say that `x` is less than every element in `s`.
```
assert forall y :: y in s' ==> string_le(x, y);
assert forall y :: y in s ==> string_le(x, y);
```
Case 2: `!(x <= x')`. From totality, we have that `x' <= x`. Since we know from the inductive hypothesis that `x'` is the minimum of `s'` and `s` is `s'` with the element `x`, we can conclude that `x'` is the smallest element of `s`.
```
assert !string_le(x, x');
assert string_le(x', x);
assert forall y :: y in s ==> string_le(x', y);
```
With that, we've proven that a smallest string exists! Here's the lemma in its entirety:
```
lemma string_smallest_exists(s: set<string>)
requires s != {}
decreases s
ensures exists x :: x in s && forall y :: y in s ==> string_le(x, y)
{
string_le_properties();
var x :| x in s;
// Base Case
if s == {x} {
assert forall y :: y in s ==> y == x;
assert forall y :: y in s ==> string_le(x, y);
// Inductive Case
} else {
var s' := s - {x};
assert s' != {};
string_smallest_exists(s');
var x' :| x' in s' && forall y :: y in s' ==> string_le(x', y);
assert x != x';
if string_le(x, x') {
assert forall y :: y in s' ==> string_le(x, y);
assert forall y :: y in s ==> string_le(x, y);
} else {
// x' is smaller than x
assert !string_le(x, x');
assert string_le(x', x);
assert forall y :: y in s ==> string_le(x', y);
}
}
}
```
### Select the smallest element from a set
Now that we have determined that a minimum exists in a set, we can use these lemmas to establish that we can uniquely determine the element that we select based on the ordering.
```
function select_string_from_set(collection: set<string>): string
requires collection != {}
{
string_le_properties();
string_smallest_exists(collection);
var value :| value in collection && forall y | y in collection :: string_le(value, y);
value
}
```
### Conclusion
Revisiting our iteration example, we can use our new `select_string_from_set` function to iterate over a set of strings in a pure deterministic function. More specifically, we'll visit all the elements in the collection in the order defined by our relation.
```
function iterate_helper(collection: set<string>, acc: seq<string>): seq<string>
decreases collection
{
if collection == {} then acc
else
var x := select_string_from_set(collection);
var newAcc := acc + [x];
var newCollection := collection - {x};
iterate_helper(newCollection, newAcc)
}
```
From here you can generalize beyond a set of strings, as long as you're able to prove the properties of a total order. The full code for our string sets example is below:
```
function string_le(s1: string, s2: string): bool
decreases |s1| + |s2|
{
if |s1| == 0 && |s2| > 0 then
true
else if |s1| > 0 && |s2| == 0 then
false
else if |s1| == 0 && |s2| == 0 then
true
else
assert(|s1| > 0);
assert(|s2| > 0);
var c1 := s1[0];
var c2 := s2[0];
if c1 < c2 then
true
else if c1 > c2 then
false
else
string_le(s1[1..], s2[1..])
}
lemma string_le_reflexive()
ensures forall s :: string_le(s ,s)
{
forall s ensures string_le(s, s)
{
string_le_reflexive_helper(s);
}
}
lemma string_le_reflexive_helper(s1: string)
ensures string_le(s1, s1)
{}
lemma string_le_totality()
ensures forall s1, s2 :: string_le(s1, s2) || string_le(s2, s1)
{
forall s1, s2 ensures string_le(s1, s2) || string_le(s2, s1)
{
string_le_totality_helper(s1, s2);
}
}
lemma string_le_totality_helper(s1: string, s2: string)
ensures string_le(s1, s2) || string_le(s2, s1)
{}
lemma string_le_antisymmetric()
ensures forall s1, s2 :: string_le(s1, s2) && string_le(s2, s1) ==> s1 == s2
{
forall s1, s2 | string_le(s1, s2) && string_le(s2, s1)
ensures s1 == s2
{
string_le_antisymmetric_helper(s1, s2);
}
}
lemma string_le_antisymmetric_helper(s1: string, s2: string)
requires string_le(s1, s2)
requires string_le(s2, s1)
ensures s1 == s2
{}
lemma string_le_transitive()
ensures forall s1, s2, s3 :: string_le(s1, s2) && string_le(s2, s3) ==> string_le(s1, s3)
{
forall s1, s2, s3 | string_le(s1, s2) && string_le(s2, s3)
ensures string_le(s1, s3)
{
string_le_transitive_helper(s1, s2, s3);
}
}
lemma string_le_transitive_helper(s1: string, s2: string, s3: string)
requires string_le(s1, s2)
requires string_le(s2, s3)
ensures string_le(s1, s3)
{}
lemma string_le_properties()
ensures forall s :: string_le(s, s)
ensures forall s1, s2 :: string_le(s1, s2) && string_le(s2, s1) ==> s1 == s2
ensures forall s1, s2, s3 :: string_le(s1, s2) && string_le(s2, s3) ==> string_le(s1, s3)
ensures forall s1, s2 :: string_le(s1, s2) || string_le(s2, s1)
{
string_le_reflexive();
string_le_antisymmetric();
string_le_transitive();
string_le_totality();
}
lemma string_smallest_exists(s: set<string>)
requires s != {}
decreases s
ensures exists x :: x in s && forall y :: y in s ==> string_le(x, y)
{
string_le_properties();
var x :| x in s;
if s == {x} {
assert forall y :: y in s ==> y == x;
assert forall y :: y in s ==> string_le(x, y);
} else {
// For sets with more than one element, we use induction-like reasoning
var s' := s - {x};
assert s' != {};
string_smallest_exists(s');
var x' :| x' in s' && forall y :: y in s' ==> string_le(x', y);
assert x != x';
if string_le(x, x') {
assert forall y :: y in s' ==> string_le(x, y);
assert forall y :: y in s ==> string_le(x, y);
} else {
// x' is smaller than x
assert !string_le(x, x');
assert string_le(x', x);
assert forall y :: y in s ==> string_le(x', y);
}
}
}
function select_string_from_set(collection: set<string>): string
requires collection != {}
{
string_le_properties();
string_smallest_exists(collection);
var value :| value in collection && forall y | y in collection :: string_le(value, y);
value
}
function iterate_helper(collection: set<string>, acc: seq<string>): seq<string>
decreases collection
{
if collection == {} then acc
else
var x := select_string_from_set(collection);
var newAcc := acc + [x];
var newCollection := collection - {x};
iterate_helper(newCollection, newAcc)
}
```

View file

@ -6,7 +6,7 @@ tags: [ "Amateur Radio" ]
medium_enabled: true medium_enabled: true
--- ---
I feel like Ham Radio has been hiding in the background as I move through life. I knew someone that kept a Ham radio in his car, Noah talks about it frequently on his [podcast](https://asknoahshow.com/), and it seemed like the next step after [playing with](https://github.com/brandon-rozek/radiotuner) [software defined radio](https://www.amazon.com/RTL-SDR-Blog-RTL2832U-Software-Telescopic/dp/B011HVUEME/ref=sr_1_3). I feel like Ham Radio has been hiding in the background as I move through life. I knew someone that kept a Ham radio in his car, Noah talks about it frequently on his [podcast](http://www.asknoahshow.com/), and it seemed like the next step after [playing with](https://github.com/brandon-rozek/radiotuner) [software defined radio](https://www.amazon.com/RTL-SDR-Blog-RTL2832U-Software-Telescopic/dp/B011HVUEME/ref=sr_1_3).
One of the things that I think pushed me over to wanting to get my Technician's license is the discovery of [digital data modes](http://www.arrl.org/digital-data-modes). Hams even have their own [email](https://www.winlink.org/)! One of the things that I think pushed me over to wanting to get my Technician's license is the discovery of [digital data modes](http://www.arrl.org/digital-data-modes). Hams even have their own [email](https://www.winlink.org/)!

View file

@ -204,17 +204,7 @@ We'll have to add the following contents to `theme/layouts/shortcodes/displayOnl
{{ $url := urls.Parse (.Get 0) }} {{ $url := urls.Parse (.Get 0) }}
{{ $status_id := index (last 1 (split $url.Path "/")) 0 }} {{ $status_id := index (last 1 (split $url.Path "/")) 0 }}
{{ $api_url := printf "%s://%s/api/v1/statuses/%s" $url.Scheme $url.Host $status_id }} {{ $api_url := printf "%s://%s/api/v1/statuses/%s" $url.Scheme $url.Host $status_id }}
{{ $dataJ := dict }} {{ $dataJ := getJSON $api_url }}
{{ $url := $api_url }}
{{ with try (resources.GetRemote $url) }}
{{ with .Err }}
{{ errorf "Unable to get remote resource %s: %s" $url . }}
{{ else with .Value }}
{{ $dataJ = . | transform.Unmarshal }}
{{ else }}
{{ errorf "Unable to get remote resource %s" $url }}
{{ end }}
{{ end }}
{{ with $dataJ }} {{ with $dataJ }}
{{ if ne .content "" }} {{ if ne .content "" }}

View file

@ -1,22 +0,0 @@
---
title: "Embrace the Heat"
date: 2025-06-08T20:36:54-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
It's summer and I'm currently in Austin, Texas, where the temperature ranges between 85 F when we had a recent thunderstorm to 100 F when there are no clouds in the sky.
I don't currently have a car so I rely on public transportation and walking to get around. As such, I'm consistently exposed to the heat. On the weekends, there is a strong temptation to hunker down and enjoy my air-conditioned apartment. However, the part of me that loves going out and exploring wins in the end.
As with any outdoor adventure, it's always important to be prepared. I don't leave my apartment without the following three items: bucket hat, sunglasses, and a water pack. Out of these, I would say the most important is drinking lots of water. It's the best way to [regulate body temperature](https://www.cdc.gov/healthy-weight-growth/water-healthy-drinks/index.html) after all. Also, it's better to start your day early, before the temperatures climb. Even after the sun goes down, it takes a while for the temperature to drop.
While browsing Reddit, I came across the phrase "Embrace the Heat." In my adventures, I see plenty of people eating outdoors, walking on trails, and paddle boarding on the Colorado river. It says a lot about human resiliency that we make the most out of any situation.
Yesterday, I rented a bicycle from Cap Metro and rode along Lady Bird lake for two hours. Before that I've been graced by the presence of the [Austin Troll Malin](https://peasepark.org/pease-park-troll), and I'm looking forward to kayaking at Barton Springs.
If you happen to visit Austin and want an indoor activity, I recommend visiting the [state capitol](https://tspb.texas.gov/plan/tours/tours.html). They allow visitors to sit in the gallerie and observe when the state house and senate is in session which is pretty cool to witness.
Otherwise, embrace the heat. Wear light clothes and come prepared to sweat.

View file

@ -1,16 +0,0 @@
---
title: "Exploring via Public Transit"
date: 2025-06-15T21:38:02-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
Last weekend, on my way back north from visiting downtown, I took a break near the Crestview lightrail station. There, I had a wonderful meal at the [Kura revolving sushi bar](https://kurasushi.com/locations/austin-tx-airport-blvd/). Afterwards, I walked around the [Kinokuniya Bookstore](https://usa.kinokuniya.com/stores-kinokuniya-austin). Honestly, this spot is not something I would've naturally discovered on my own.
![Image of Sushi Conveyor Belt](/files/images/blog/202506071440.png)
Using public transportation is a great way to explore the neighborhoods around you. Busses often don't take highways, and instead will take you through areas that you would've otherwise skipped. You can find many great restaurants to eat in the Bay Area right next to the Mountain View Caltrain station. A few years ago when Clare and I visited Portland, Maine, we got to explore the thousand islands by a [mail boat](https://www.cascobaylines.com/maine-boat-tours/specialty-cruises/mailboat/).
Even if you have a car, it's worth taking a look at the transit maps to see if there are any hidden gems.

View file

@ -1,258 +0,0 @@
---
title: "Filesystem as a persistent key-value store in Python"
date: 2025-04-27T13:39:49-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
The first level within the [five levels of configuration languages](https://beza1e1.tuxen.de/config_levels.html) is a string in a file. The example that Andreas gives in his blog post is enabling/disabling energy aware scheduling in the kernel.
```bash
# Read the current value
cat /proc/sys/kernel/sched_energy_aware
```
This approach does not require using any custom serializers or deserializers. Instead, the user or program only needs to navigate and read/write the filesystem.[^1]
[^1]: You likely want to make sure that your program is sufficiently isolated. Either by running it within it's own container or setting up custom permissions on the files.
However, having to write filesystem code is tedious. What we want is a dictionary that we can write and read from that handles all of the filesystem procedures for us.
In this post, we'll go over how to achieve this in Python. By the end we'll be able to do the following:
```bash
# Create key-value store
mkdir /tmp/kvs
# Add value "Brandon" to key "name"
echo "Brandon" | tee /tmp/kvs/name
```
```python
# Set /tmp/kvs as the root of our key-value store
kvs = FSDict("/tmp/kvs")
# Read the key 'name'
print("Name:", kvs['name'])
# Name: Brandon
```
## Creating the library
To emulate reading and writing from a dictionary, we will create a custom class and implement the `__setitem__` and `__getitem__` methods.
```python
class FSDict:
def __init__(self, base_directory: Optional[str] = None):
self.base_directory: Optional[str] = None
if base_directory is not None:
self.set_base_directory(base_directory)
def set_base_directory(self, base_directory: str):
assert isinstance(base_directory, str)
if os.path.isfile(base_directory):
raise Exception("base_directory is an existing file not a folder.")
self.base_directory = base_directory
if not os.path.exists(base_directory):
os.makedirs(base_directory)
# ...
```
From here, we can declare a folder as the root of our key-value store and if it does not exist then the code will create it for us.
```python
kvs = FSDict("/tmp/kvs")
```
When we write `kvs['name']`, we want it to read from the file or folder `/tmp/kvs/name`. Our next method then will create the path.
```python
def get_path(self, key: str) -> str:
assert self.base_directory is not None
if not isinstance(key, str):
raise ValueError("key must be of type str")
return os.path.join(self.base_directory, key)
```
Just like in our initial kernel example, we want a way to have nested folders. Therefore, in this API when we read and write from the KVS, if the value is a `str` then we're writing it's contents to a file, otherwise if it is a `FSDict` then we'll create the folder if it does not already exist.
To write to our key-value store:
```python
def __setitem__(self, key: str, value: Union[str, "FSDict"]):
assert isinstance(value, (str, FSDict)), "Value must either be of type str or FSDict"
path = self.get_path(key)
# If we're writing a FSDict, then create
# a folder if it doesn't already exist.
if isinstance(value, FSDict):
value.set_base_directory(path)
return None
# Otherwise, assume we're writing a
# string to a file
with open(path, "w") as f:
f.write(value)
```
To read from our key-value store:
```python
def __getitem__(self, key: str) -> Union[str, "FSDict"]:
path = self.get_path(key)
if not os.path.exists(path):
raise KeyError(key)
# Return a FSDict if it's a folder
if os.path.isdir(path):
return FSDict(path)
# Otherwise, assume we're reading a file
with open(path, "r") as f:
return f.read()
```
With that, we have the minimum viable product for reading and writing to our dictionary-like class!
```python
kvs = FSDict("/tmp/kvs")
kvs['name'] = 'Brandon'
print(kvs['name'])
# Prints 'Brandon'
```
The base dictionary class has other methods that make our lives easier. Let's implement a few more.
```python
def __delitem__(self, key: str):
path = self.get_path(key)
if not os.path.exists(path):
raise KeyError(key)
# If the key is a folder, recursively
# remove all contents of that folder
if os.path.isdir(path):
shutil.rmtree(path)
return None
# Otherwise, remove the file
os.remove(path)
def __contains__(self, key: str) -> bool:
path = self.get_path(key)
return os.path.exists(path)
def keys(self) -> List[str]:
assert self.base_directory is not None
return os.listdir(self.base_directory)
def __repr__(self) -> str:
return f"FSDict(base_directory={self.base_directory})"
```
Extending our last example, this gives us:
```python
# Show all keys
print(kvs.keys())
# Result: ['name']
# Check if a key is in the key-value store
print('name' in kvs)
# Result: True
# Delete a key-value by it's key
del kvs['name']
# Check if it still exists in our key-value store
print('name' in kvs)
# Result: False
```
## Conclusion
The class `FSDict` provides a simple way in Python to use the filesystem as a persistent key-value store. Unlike storing everything in a single file or database, we do not need special serializers or deserializers to access to data. Outside the program we can use `echo` and `cat` in our terminals to interact with the key-value store.
The full code is as follows:
```python
from typing import List, Optional, Union
import os
import shutil
class FSDict:
def __init__(self, base_directory: Optional[str] = None):
self.base_directory: Optional[str] = None
if base_directory is not None:
self.set_base_directory(base_directory)
def set_base_directory(self, base_directory: str):
assert isinstance(base_directory, str)
if os.path.isfile(base_directory):
raise Exception("base_directory is an existing file not a folder.")
self.base_directory = base_directory
if not os.path.exists(base_directory):
os.makedirs(base_directory)
def get_path(self, key: str) -> str:
assert self.base_directory is not None
if not isinstance(key, str):
raise ValueError("Key must be of type str")
return os.path.join(self.base_directory, key)
def __setitem__(self, key: str, value: Union[str, "FSDict"]):
assert isinstance(value, (str, FSDict)), "Value must either be of type str of FSDict"
path = self.get_path(key)
if isinstance(value, FSDict):
value.set_base_directory(path)
return None
# Assuming value is a str
with open(path, "w") as f:
f.write(value)
def __getitem__(self, key: str) -> Union[str, "FSDict"]:
path = self.get_path(key)
if not os.path.exists(path):
raise KeyError(key)
if os.path.isdir(path):
return FSDict(path)
# Assume it's a file
with open(path, "r") as f:
return f.read()
def __delitem__(self, key: str):
path = self.get_path(key)
if not os.path.exists(path):
raise KeyError(key)
if os.path.isdir(path):
shutil.rmtree(path)
return None
# Assume it's a file
os.remove(path)
def __contains__(self, key: str) -> bool:
path = self.get_path(key)
return os.path.exists(path)
def keys(self) -> List[str]:
assert self.base_directory is not None
return os.listdir(self.base_directory)
def __repr__(self) -> str:
return f"FSDict(base_directory={self.base_directory})"
```

View file

@ -1,182 +0,0 @@
---
title: "Hashing Based on Word (Emoji?) Lists"
date: 2024-12-30T19:13:35-05:00
draft: false
tags: []
math: true
medium_enabled: false
---
When I go to download Fedora Workstation 41, it gives me an option to verify the ISO download with a SHA-256 checksum.
```
a2dd3caf3224b8f3a640d9e31b1016d2a4e98a6d7cb435a1e2030235976d6da2
```
The idea is that when I download the ISO, I run
```bash
sha256sun Fedora-Workstation-Live-x86_64-41-1.4.iso
```
The output of the command should match the given checksum. If not, I should assume that I have a fraudulent ISO.[^1]
[^1]: You might ask, how do we know that the checksum hasn't been tampered with? Fedora's solution is PGP-signatures, but that's outside the scope of this post.
SHA-256 is one particular [*Cryptographic hash function*](https://en.wikipedia.org/wiki/Cryptographic_hash_function). There are many others, but these algorithms are typically used for some form of verification. These algorithms have the following properties:
- **Deterministic**: When you run it on the same input, you get the same output.
- **Fixed-Length:** Inputs can be as long as you want, but the output has a fixed-length.
- **Pre-image Resistant**: All inputs are equally likely to produce a particular hash value.
- **Second Pre-Image Resistant**: All inputs are equally likely to produce the same hash value as a particular input.
- **Collision Resistant**: It's difficult to find any two messages that have the same hash value.
I won't get into these properties in this post. Feel free to read the Wikipedia article linked above to learn more.
Another example of a verification task is password checking. The idea is that (hopefully most) websites don't actually store your passwords, but a hash value of them on their servers. When you send in your password, they then hash it and make sure the hash values match.
**Please don't use SHA-256 for password checking.** Unfortunately, many people use short/simple passwords, and re-use them across multiple websites. If an attacker gets a hold of your password hash database, they can run the hash function on a bunch of common passwords and see if any of those hashes match what's inside the database. Best practices evolve over time, so please do your research when implementing authentication.
Krishna wrote a [blog post](https://chittur.dev/cs/2020/04/11/readable-hashes.html) a few years ago advocating for the use of *human-readable* hash values. Instead of using a random sequence of characters, why don't we use a random sequence of words instead?
As a community, we have agreed on what possible characters a SHA-256 checksum can consist of. That is, alphanumeric characters a-z and 0-9. However, *we don't agree on what words we should use*.
Lifting from Krishna's blog post, there are [multiple](https://github.com/singpolyma/mnemonicode) [readable](https://tools.ietf.org/html/rfc1751) [hash](https://github.com/fpgaminer/hash-phrase) ideas out there. They each use different wordlists. Even Krishna's approach uses a different one!
I'll go over a general approach on how to implement a hash function for any arbitrary wordlist. Then I'll argue, that we should consider using Emojis for our wordlist.
### A general approach to hashing with word lists
Instead of directly worrying about how to create a hash function, we're going to piggy-back off an existing one. For example, consider the SHA-256 algorithm. This takes an input and produces a 256-bit number.
Given a wordlist of $N$ words, we want to produce a sequence of words that captures at least the amount of information within a 256-bit number. The number of bits that a word represents in our wordlist is:
$$
wbits = \lfloor log_2(N) \rfloor
$$
From this, we can derive how many words we need to capture a 256-bit number
$$
outlen = \lceil 256 / wbits \rceil
$$
Consider an arbitrary input `x` and hash it to create `h`
```python
h = int(hashlib.sha256(x).hexdigest(), 16)
```
For the UTF-8 encoded string `"test"`, we'll get the following binary representation:
```
1001111110000110110100001000000110001000010011000111110101100101100110100010111111101010101000001100010101011010110100000001010110100011101111110100111100011011001010110000101110000010001011001101000101011101011011000001010110110000111100000000101000001000
```
To determine which word from the word lists to use, we'll consider binary sequences of length `wbits`. Since 256 might not be divisible by `wbits`, we might need to pad a certain number of zeros at the end.
```bash
bits_needed = (math.ceil(256 / outlen) * outlen) - 256
h = h << bits_needed
```
For sake of example, let's say that `wbits` is equal to 11. Then the first binary sequence is `10011111100`. This corresponds to the 1276th word in our word list.
Iterate through all these subsequences to have a list of indices:
```python
indices = []
for i in range(outlen):
num = (h >> (wbits * i)) & (2**wbits - 1)
indices.append(num)
```
Consider the word list `wordlist`, we can use the indices to print out the hashed version of our input using the word list!
```python
words = [wordlist[i] for i in indices]
print(" ".join(words))
```
The full script is located at the bottom of this post.
### Which wordlist should I use?
The smaller our word list length $N$ is, the more words we'll need to output for the hash. Ideally, we use a large word list. As discussed before, there's many different opinions on what properties a word list should have. Some believe that a word list should only contain [easy-to-pronounce](https://github.com/singpolyma/mnemonicode) words. Many don't want profanity in their word lists.
Joseph Bonneau wrote a [blog post](https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases) describing all the criteria he used when crafting his choice of 7776 words. The EFF endorses this word list for use in password generation, and the [diceware](https://github.com/ulif/diceware) Python package also uses this list.
What's important though, is that both parties agree on what word list to use.
When designing a word list, one issue to look out for is the [Prefix Code Problem](https://en.wikipedia.org/wiki/Prefix_code). Some words are concatenations of other words, for example: rainbow, today, sunflower, etc. If you don't use a delimiter between words, then you'll lose information since we can't distinguish whether it's multiple words or just one word.
Returning to the EFF word list, here's how we can obtain the word list as of the time of writing:
```bash
curl https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt | cut -f2 > eff_wordlist.txt
```
In order to capture the 256-bit hash, we need to use 22 words from the EFF word list. The hash for the UTF-8 encoded version of "test" is:
```
duress amiss antler atop item illicitly blimp anchor gigahertz consoling chance atonable frugality hardhead freeing bust crowd drool editor earful detective fiction
```
Words are nice and all. But what about Emojis? The Unicode Consortium maintains a list of [thousands of emojis](https://unicode.org/emoji/charts/full-emoji-list.html). Like words, emojis are very easy for our eyes to parse.
As of the time of writing, we're at version 16 of the Emoji character list. Here's a crude parser for getting a list of emojis.
```bash
curl https://unicode.org/Public/emoji/16.0/emoji-test.txt | grep -v "^#" | grep -oP '#\s*\K.*?(?=\s*E)' > emojis.txt
```
This produces a list of 5042 emojis. Similarly, to capture a 256-bit hash, we'll need to use 22 emojis. For the UTF-8 encoded version of "test", the hash is
```
🧍🏼‍♂️ 💜 🫷 🫵🏽 👩🏿‍❤‍👩🏾 👨🏼‍❤️‍👨🏼 👨🏾 💤 🤹 🧑🏿‍🎨 🤦🏼‍♂ 🫵🏼 🤸🏾 👨🏽‍❤️‍💋‍👨🏼 🚴🏿‍♂️ 🙎🏿‍♀️ 💂‍♀ 🚶🏾‍♀️‍➡️ 🧎🏽‍♀️‍➡ 🧎🏾 🧙🏿‍♂ 🏄🏻‍♂️
```
Does your browser show all the emojis?
While I'm advocating for the use of emojis, there are two problems that I currently recognize:
- New emojis get introduced regularly. Luckily the dataset is versioned, so you can state to verify using the version 16 set.
- Not all applications and fonts support newer emojis. I use Konsole with Noto Sans and "🫩" is not recognized.
Though I feel that emojis are richer than a standard English based word list. Also, it's friendly to those who don't speak English as well!
The full script from before:
```python
import argparse
import hashlib
import math
parser = argparse.ArgumentParser(description="Create a hash from a wordlist")
parser.add_argument("wordlist", type=str, help="Path to wordlist")
args = vars(parser.parse_args())
wordlist = []
# File must have one word per line
with open(args['wordlist']) as f:
wordlist = f.read().splitlines()
assert len(wordlist) > 0
# Number of bits we can use to index the wordlist
wlbits = math.floor(math.log(len(wordlist)) / math.log(2))
outlen = math.ceil(256 / wlbits)
bits_needed = (math.ceil(256 / outlen) * outlen) - 256
data = input("")
sha256_data = hashlib.sha256(data.encode("utf-8"))
encoded_data = int(sha256_data.hexdigest(), 16) << bits_needed
indices = []
for i in range(outlen):
num = (encoded_data >> (wlbits * i)) & (2**wlbits - 1)
indices.append(num)
words = [wordlist[i] for i in indices]
print(" ".join(words))
```

View file

@ -32,7 +32,7 @@ There are two types of hidden that I can think of:
- You don't want any pages within unlisted to render at all. - You don't want any pages within unlisted to render at all.
- You want it to render, but not appear in the section listing - You want it to render, but not appear in the section listing
For the first case, [Filosophy suggests](https://web.archive.org/web/20210125075337/https://filosophy.org/code/disabling-a-specific-section-in-hugo/) to rename the section so that it starts with a dot. For example, `.unlisted`. For the first case, [Filosophy suggests](https://filosophy.org/code/disabling-a-specific-section-in-hugo/) to rename the section so that it starts with a dot. For example, `.unlisted`.
For the second case, we need to introduce a page variable to help us choose when to display it. Let us call that page variable `hidden`. To set it to true, you need to add it to the frontmatter of `content/unlisted/_index.md`. For the second case, we need to introduce a page variable to help us choose when to display it. Let us call that page variable `hidden`. To set it to true, you need to add it to the frontmatter of `content/unlisted/_index.md`.

View file

@ -1,42 +0,0 @@
---
title: "Rolling out my own CDN with GeoDNS"
date: 2024-12-28T07:11:16-05:00
draft: false
tags: []
math: false
medium_enabled: false
---
I noticed when looking at my [monitoring](https://brandonrozek.com/blog/website-status-checking/) that accessing my website from Asia takes almost a full second to load.
![](/files/images/blog/photo_2024-12-25_22-16-17.jpg)
I apologize to all my visitors in that segment of the green orb. Please do write to me to tell me you exist though! I'm always happy to hear from readers of my blog.
> Why don't you use Cloudflare?
You see friend, I believe in a decentralized web. I want to do my part in not contributing to the monopoly.
Also, I'm not a huge fan of how most CDNs work. I don't want to have my DNS tied to a CDN provider.
This gets me thinking, can I roll out my own CDN? It turns out we can! For the purposes of this personal website, we don't need servers in every country in the globe.
The Internet as we know it, is enabled through many undersea cables. Looking at the [cable map](https://www.submarinecablemap.com/) and the performance timings I have, if I stick a server in Singapore, it should help bring down the load times in Japan and Austrialia as well.
My website is entirely static. This makes keeping everything in sync simple. I only need to make sure that I have a copy of my website on both servers.
Luckily, I was able to snag a VPS in Singapore from [GreenCloud](https://greencloudvps.com/) for only $22/year during Black Friday. In New York, at the time of writing I'm using [EasyVM](https://easyvm.net/).
Now both servers have `nginx` installed and have the files needed to serve my website to visitors. However, if me in New York tries to connect to a server in Singapore, then I'll be the one waiting for 874ms!
This is where GeoDNS comes in. The DNS server analyzes the IP address of the visitor requesting my websites IP and returns the server that it thinks is the closest!
Not every DNS provider has this feature. At the time of writing, I'm using [Bunny DNS](https://bunny.net/dns/). The first million queries is free, and then it's $0.30 for every million after that. For the month of December, Bunny has responded to 1,166,405 queries for my domain which luckily doesn't break the bank for me.
In the DNS zone, I specify the IP addresses of the two servers and include the GPS coordinates of where they sit. If you don't know that information, you can use a website like [ipinfo.io](https://ipinfo.io/) to find out.
![](/files/images/blog/202412252243.png)
With my extra server and GeoDNS set up, I now have load times under 350ms in all the regions my monitoring service checks!
![](/files/images/blog/202412252248.png)

View file

@ -113,7 +113,7 @@ We can show this using a theorem from mathlib!
exact eq_or_eq_neg_of_sq_eq_sq n 3 H1_1 exact eq_or_eq_neg_of_sq_eq_sq n 3 H1_1
``` ```
[(Quite the long name...)](https://web.archive.org/web/20240106030817/https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/GroupPower/Ring.html#eq_or_eq_neg_of_sq_eq_sq) [(Quite the long name...)](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/GroupPower/Ring.html#eq_or_eq_neg_of_sq_eq_sq)
Lastly, we combine the two subset proofs to show equality Lastly, we combine the two subset proofs to show equality

View file

@ -18,7 +18,7 @@ I opened up mini-circuits and was greeted with the following table. (Shorted for
| LZV-22+ | 0.1 | 200 | 43 | 8.9 | 42 | 52 | 1.4 | 4 | 24 | 6000 | | LZV-22+ | 0.1 | 200 | 43 | 8.9 | 42 | 52 | 1.4 | 4 | 24 | 6000 |
| ZHL-1W-63-S+ | 600 | 6000 | 35 | 12 | 30 | 35 | 2.5 | 3.5 | 15 | 1000 | | ZHL-1W-63-S+ | 600 | 6000 | 35 | 12 | 30 | 35 | 2.5 | 3.5 | 15 | 1000 |
### Definitions <u>Definitions</u>
F Low: Lowest frequency supported by the power amplifier F Low: Lowest frequency supported by the power amplifier

View file

@ -1,103 +0,0 @@
---
title: "Listing Offline Pages with Service Workers"
date: 2024-12-07T10:05:20-05:00
draft: false
tags: []
math: false
medium_enabled: false
---
Using web service workers, you can set it up so that visitors [have an offline experience](/blog/2015-11-14-service-workers/) with your website. In my original blog post, I wrote about how to cache pages, and how to show them when the visitor lacks an Internet connection, or a special [offline page](/offline) instead.
This, however, doesn't list what pages are cached on their device. Wouldn't it make sense to show this in the offline page? It was kinda crazy that I didn't do this before, so in this post we'll go over how to showcase the list of saved offline pages.
---
Recall that web workers give us access to the [cache interface](https://developer.mozilla.org/en-US/docs/Web/API/Cache). From it, we can access any number of caches.
```javascript
const cache = await caches.open('v1::website')
```
A cache is a dictionary, with `Requests` objects mapped to `Response` objects. We can filter within our cache for request-response pairs that match a particular URL structure or has a certain content type.
```javascript
for (const request of await cache.keys()) {
const url = request.url;
if (url.includes('/blog')) {
const response = await cache.match(request)
if (response.headers.get('content-type').includes('text/html')) {
process(request, response);
}
}
}
```
For my offline pages listing, I want it to look like the following:
- [Monitoring my Hard Drives with SMART Attributes](/blog/monitoring-disks-smartattributes/) (visited 20 days ago)
- [Adventures in Bird Watching](/blog/adventures-in-bird-watching) (visited 40 days ago)
We can get the title by searching for the `<title>` tag within the response object.
```javascript
const body = response.text()
const title = body.match(/<title>(.*)<\/title>/)[1]
```
For the last visited, we can look at the response headers.
```javascript
const visited = new Date(post.headers.get('date'))
```
Let's say we stored all of this within a list
```javascript
result.push({url, title, visited})
```
We can then iterate over `result` and add list items within a unordered-list `<ul>`.
```javascript
const el = document.querySelector('#offline-posts');
if (result.length) {
el.innerHTML = result
.map((res) => {
let html = `<li>
<a href="${res.url}">${res.title}</a>
<small><span title="${res.visited.toString()}">
(visited ${daysAgo(res.visited)})
</span></small>
</li>`;
return html;
})
.join('\n');
}
```
The function `daysAgo` returns an easy to read time delta between the visited timestamp and now.
```javascript
function daysAgo(date) {
date.setHours(0, 0, 0, 0);
const time = date.getTime();
const today = new Date();
today.setHours(0, 0, 0, 0);
const now = today.getTime();
const delta = ((now - time) / 1000 / 60 / 60 / 24) | 0;
if (delta < 1) {
return 'today';
}
if (delta === 1) {
return 'yesterday';
}
return `${delta | 0} days ago`;
}
```

View file

@ -8,12 +8,13 @@ guid: https://brandonrozek.com/2017/03/2052-revision-v1/
permalink: /2017/03/2052-revision-v1/ permalink: /2017/03/2052-revision-v1/
tags: ["Statistics"] tags: ["Statistics"]
--- ---
![](/files/images/blog/LifeExpectancyBoxplot.png) ![](https://brandonrozek.com/wp-content/uploads/2017/03/LifeExpectancyBoxplot.png)
## Do females live longer than males? ## Do females live longer than males?
It is well known that females live longer than males, but does that statement hold statistically? Matthew Martinez and I set out to find out. It is well known that females live longer than males, but does that statement hold statistically? Matthew Martinez and I set out to find out.
<!--more-->
## Population and the hypothesis ## Population and the hypothesis
@ -25,9 +26,9 @@ HA: The average female life expectancy is higher than the average male life expe
## Data preparation ## Data preparation
Since the website gives us an overlook at all of the counties in the United States we want to take a small sample of that so we can perform statistics. Using the entire dataset will result in looking at population parameters which doesn't leave room for inference. Since the website gives us an overlook at all of the counties in the United States we want to take a small sample of that so we can perform statistics. Using the entire dataset will result in looking at population parameters which doesn&#8217;t leave room for inference.
A random number was chosen to pick the state and then the county. This was done a total of 101 times. The CSV file is located [here](/data/LifeExpectancy.csv) for convenience. A random number was chosen to pick the state and then the county. This was done a total of 101 times. The CSV file is located [here](https://brandonrozek.com/wp-content/uploads/2017/03/LifeExpectancy.csv) for convenience.
## R Programming ## R Programming
@ -45,9 +46,9 @@ femaleExpectancy = LifeExpectancy$Life.Expectancy.Female
## Summary Statistics ## Summary Statistics
Before we begin our inferential statistics, it is a good idea to look at what we have in our sample. It will give us a good feeling for what we're working with and help us answer some questions involving the assumptions in parametric tests. Before we begin our inferential statistics, it is a good idea to look at what we have in our sample. It will give us a good feeling for what we&#8217;re working with and help us answer some questions involving the assumptions in parametric tests.
We're interested in the minimum, mean, maximum, and interquartile range of the data We&#8217;re interested in the minimum, mean, maximum, and interquartile range of the data
```R ```R
# Summary statistics # Summary statistics
@ -64,7 +65,7 @@ Looking at the table below, we can see that the average male lives to be around
summary summary
## Min Mean Max IQR ## Min Mean Max IQR
## Male 69.0 74.952 80.9 2.775 ## Male 69.0 74.952 80.9 2.775
## Female 76.1 80.416 84.1 2.350 ## Female 76.1 80.416 84.1 2.350</code></pre>
``` ```
## Inferential Statistics ## Inferential Statistics
@ -77,11 +78,11 @@ Since our data is quantitative in nature, we will attempt to perform a two sampl
Performing a t-test comes with several assumptions we need to check before confidently reporting our results. Performing a t-test comes with several assumptions we need to check before confidently reporting our results.
**Independence Condition:** One county's life span does not affect the lifespan of another. <u>Independence Condition:</u> One county&#8217;s life span does not affect the lifespan of another.
**Independent groups assumption:** The lifespan of a male does not directly impact a lifespan of a female. <u>Independent groups assumption:</u> The lifespan of a male does not directly impact a lifespan of a female.
**Nearly Normal Condition:** We need to check the histograms to see if they're unimodal and symmetric and check to see if any outliers exist <u>Nearly Normal Condition:</u> We need to check the histograms to see if they&#8217;re unimodal and symmetric and check to see if any outliers exist
The male life expectancy distribution appears to be unimodal and symmetric. The male life expectancy distribution appears to be unimodal and symmetric.
@ -90,7 +91,7 @@ The male life expectancy distribution appears to be unimodal and symmetric.
hist(maleExpectancy, main = "Male Life Expectancy", xlab = "Age") hist(maleExpectancy, main = "Male Life Expectancy", xlab = "Age")
``` ```
![](/files/images/blog/maleLifeExpectancyHist.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/03/maleLifeExpectancyHist.png" width="672" />
Same with the female life expectancy distribution Same with the female life expectancy distribution
@ -98,16 +99,15 @@ Same with the female life expectancy distribution
hist(femaleExpectancy, main = "Female Life Expectancy", xlab = "Age") hist(femaleExpectancy, main = "Female Life Expectancy", xlab = "Age")
``` ```
![](/files/images/blog/femaleLifeExpectancyHist.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/03/femaleLifeExpectancyHist.png" width="672" />
Looking at the boxplot, we can see that the IQR of the female life expectancy is higher than the one of the males. The hypothesis test will show us if this is of significant difference. On the male&#8217;s side there are two outliers. This violates the Nearly Normal Condition so we must proceed with caution in our test.
Looking at the boxplot, we can see that the IQR of the female life expectancy is higher than the one of the males. The hypothesis test will show us if this is of significant difference. On the male's side there are two outliers. This violates the Nearly Normal Condition so we must proceed with caution in our test.
```R ```R
boxplot(maleExpectancy, femaleExpectancy, names = c("Male Life Expectancy", "Female Life Expectancy"), ylab = "Age") boxplot(maleExpectancy, femaleExpectancy, names = c("Male Life Expectancy", "Female Life Expectancy"), ylab = "Age")
``` ```
![](/files/images/blog/LifeExpectancyBoxplot.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/03/LifeExpectancyBoxplot.png" width="672" />
Since the nearly normal condition was not met, we do not meet the assumptions necessary to perform a t-test. However, since the condition was violated by an outlier, let us perform a t-test with the outlier and without the outlier and compare the results. Since the nearly normal condition was not met, we do not meet the assumptions necessary to perform a t-test. However, since the condition was violated by an outlier, let us perform a t-test with the outlier and without the outlier and compare the results.
@ -175,7 +175,7 @@ Looking at the boxplot, there are no more outliers present
boxplot(maleExpectancy2, ylab = "Age", main = "Male Life Expectancy w/o Outliers") boxplot(maleExpectancy2, ylab = "Age", main = "Male Life Expectancy w/o Outliers")
``` ```
![](/files/images/blog/MLifeExpectBoxplotNoOutliers.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/03/MLifeExpectBoxplotNoOutliers.png" width="672" />
The histogram still appears to be unimodal and symmetric The histogram still appears to be unimodal and symmetric
@ -183,7 +183,7 @@ The histogram still appears to be unimodal and symmetric
hist(maleExpectancy2, xlab = "Age", main = "Male Life Expectancy w/o Outliers") hist(maleExpectancy2, xlab = "Age", main = "Male Life Expectancy w/o Outliers")
``` ```
![](/files/images/blog/MLifeExpectHistNoOutliers.png) <img src="https://brandonrozek.com/wp-content/uploads/2017/03/MLifeExpectHistNoOutliers.png" width="672" />
Without the outliers present, the nearly normal condition is now met. We can perform the t-test. Without the outliers present, the nearly normal condition is now met. We can perform the t-test.

View file

@ -2,7 +2,7 @@
title: "Modifying JSON in Rust" title: "Modifying JSON in Rust"
date: 2024-08-03T07:59:15-07:00 date: 2024-08-03T07:59:15-07:00
draft: false draft: false
tags: ["Rust"] tags: []
math: false math: false
medium_enabled: false medium_enabled: false
--- ---

View file

@ -1,101 +0,0 @@
---
title: "Naive Encodings of Transitivity within First-Order Logic"
date: 2024-12-29T07:28:05-05:00
draft: false
tags: ["Logic"]
math: true
medium_enabled: false
---
> The transitive closure of a binary relation cannot, in general, be expressed in first-order logic (FO)
In Ray Reiter's book "Knowledge in Action: Logical Foundations for Specifying and Implementing Dynamical Systems", he goes over a typical naive encoding of transitivity in first-order logic and goes over a counter-example[^1].
[^1]: Unfortunately there was an errata in Example 2.1.1. The set `T` should be described as `{(b, a), (b, b)}` instead of the typo `{(a, b), (b, b)}`. Thanks James for noticing this!
Let $G$ be a binary relation that represents whether or not there is a direct edge between two nodes.
We want to axiomatize the transitive closure into the binary relation $T$. This means we need to have a formula that holds when we have a transitive closure, and does not hold when we do not.
A naive axiomatization is the following:
$$
T(x, y) \iff G(x, y) \vee \exists z(G(x, z) \wedge T(z, y))
$$
Ray's counter-example is the following. Consider the following valuation of $G$:
```
G: {(b, b)}
```
{{< unsafe >}}
<img height="300px" src="/files/images/blog/202412280944.svg"/>
<br/>
{{< /unsafe >}}
Now consider the following valuation of $T$:
```
T: {(b, a), (b, b)}
```
We falsely state that `b` is connected to `a` via transitive closure. If our axiomatization is sound, then it should be falsified.
$$
\begin{align*}
T(b, a) &\iff G(b, a) \vee \exists z (G(b, z) \wedge T(z, a)) \\\\
&\impliedby \bot \vee (G(b, b) \wedge T(b, a)) \\\\
&\impliedby \bot \vee (\top \wedge \top) \\\\
&\impliedby \top
\end{align*}
$$
However, the formula is satisfied! Therefore, this cannot be used to axiomatize transitive closure.
That's the end of the original counter-example in the book. However, I thought it would be fun to extend the exercise.
The issue in the last example, is that we had a cycle in which we were able to define $T(b, a)$ in terms of $T(b, a)$. What if we add a constraint so that isn't the case?
$$
T(x, y) \iff G(x, y) \vee \exists z(z \ne x \wedge G(x, z) \wedge T(z, y))
$$
Does this new formula axiomatize transitive closure? The quote at the beginning begs to differ, so let's find a counter-example!
Consider the following valuations for $G$ and $T$:
```
G: {(b, a), (a, b)}
T: {(b, c), (a, c)}
```
{{< unsafe >}}
<img height="300px" src="/files/images/blog/202412281036.svg"/>
<br/>
{{< /unsafe >}}
As before, this model should not have transitive closure. Let's evaluate our modified formula.
$$
\begin{align*}
T(b, c) &\iff G(b, c) \vee \exists z (z \ne b \wedge G(b, z) \wedge T(z,c)) \\\\
&\impliedby \bot \vee (a \ne b \wedge G(b, a) \wedge T(a, c)) \\\\
&\impliedby \bot \vee (\top \wedge \top \wedge \top) \\\\
&\impliedby \top
\end{align*}
$$
$$
\begin{align*}
T(a, c) &\iff G(a, c) \vee \exists z (G(a, z) \wedge T(z, c)) \\\\
&\impliedby G(a, c) \vee (b \ne a \wedge G(a, b) \wedge T(b, c)) \\\\
&\impliedby \bot \vee (\top \wedge \top \wedge \top) \\\\
&\impliedby \top
\end{align*}
$$
Here we can see that the above valuations depending on each other.
Wikipedia has a great [article](https://en.wikipedia.org/wiki/Transitive_closure) on transitive closure including a section on its use within logic and computational complexity.
> (First-order Transitive-Closure Logic) FO(TC) is strictly more expressive than FO.

View file

@ -70,14 +70,3 @@ server {
} }
``` ```
You can test to see if this works by trying to query your IP directly using curl.
```bash
curl 173.255.230.230
```
This should return:
```
curl: (52) Empty reply from server
```

View file

@ -1,153 +0,0 @@
---
title: "Setting up Ollama with CUDA on Podman Quadlets"
date: 2025-03-29T09:59:55-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
[Open WebUI](https://www.openwebui.com/) provides a nice chat interface for interacting with LLMs over Ollama and OpenAI compatible APIs. Using [Ollama](https://ollama.com/), we can self-host many different LLMs that are open-sourced! This post documents the steps that I took in order to get Ollama working with CUDA using my Podman setup. However given how fast Machine Learning projects iterate, I wouldn't be surprised if these exact steps no longer work. In that case, I'll provide links to the official documentation which hopefully can help.
I'll assume that you have the NVIDIA driver installed on your machine. The steps vary by OS/distribution and how modern of a driver you want, but I generally recommend to stick with what's packaged in your distribution's repository. This is to minimize headaches...
With that, our first step is to install the `nvidia-container-toolkit`. This package contains a collection of libraries and scripts to help us run our GPU inside a container.
```bash
sudo dnf install nvidia-container-toolkit
```
As of this time of writing, instructions for installing the toolkit can be found on [NVIDIA's website](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html).
We can use this toolkit to generate a Common Device Interface (CDI) file which Podman will use to talk to the GPU.
```bash
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
```
**Note:** Every time you update your NVIDIA driver, you'll have to run this command.
NVIDIA also documents the steps for configuring CDI on [their website](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/cdi-support.html#running-a-workload-with-cdi).
From here, we should make sure that the NVIDIA toolkit found the appropriate GPU(s) and has set up their CDI.
```bash
nvidia-ctk cdi list
```
I only have one GPU on my machine, so it outputs something like the following:
```
INFO[0000] Found 3 CDI devices
nvidia.com/gpu=0
nvidia.com/gpu=GPU-52785a8a-f8ca-99b9-0312-01a1f59e789b
nvidia.com/gpu=all
```
If you want your container to be able to access all the GPUs, we can use the `nvidia.com/gpu=all` device interface. Otherwise, we can use a specific one.
Then, we restart Podman so that the CDI files are loaded.
```bash
sudo systemctl restart podman
```
For our first test, we'll make sure that the container can appropriately access the GPU by running the `nvidia-smi` command.
```bash
sudo podman run --rm \
--device nvidia.com/gpu=all \
docker.io/nvidia/cuda:11.0.3-base-ubuntu20.04 \
nvidia-smi
```
For my GPU it outputs:
```
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.124.04 Driver Version: 570.124.04 CUDA Version: 12.8 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3060 Off | 00000000:02:00.0 On | N/A |
| 0% 50C P8 19W / 170W | 1546MiB / 12288MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+
```
Now we are ready to set up Ollama! To save time when running our `systemd` commands, let's pull the image ahead of time.
```bash
sudo podman pull docker.io/ollama/ollama
```
We'll have to save the models somewhere, so in this example we'll save them to `/opt/ollama`.
```bash
sudo mkdir /opt/ollama
```
Let's configure the Quadlet. Save the following to `/etc/containers/systemd/ollama.container`:
```ini
[Container]
ContainerName=ollama
HostName=ollama
Image=docker.io/ollama/ollama
AutoUpdate=registry
Volume=/opt/ollama:/root/.ollama
PublishPort=11434:11434
AddDevice=nvidia.com/gpu=all
[Unit]
[Service]
Restart=always
[Install]
WantedBy=default.target
```
This file specifies the flags that we pass to the podman command:
- Publish the port 11434: This is the port we'll use when sending messages to Ollama from Open WebUI. Of course you're welcome to use other networking tricks to pull that off.
- Mount the folder `/opt/ollama` on the filesystem to `/root/.ollama` within the container: We don't want to have to re-download the LLM models each time!
For the moment of truth, let's start it!
```bash
sudo systemctl start ollama
```
I won't show in this post how to configure Open WebUI, but we can make sure that everything is working by looking at the Ollama container itself.
```bash
sudo podman exec -it ollama /bin/bash
```
We'll perform a test with a smaller model (1.2 GB):
```bash
ollama run llama3.2:1b
```
Depending on your Internet connection, this will take a couple minutes to download and load onto the GPU.
When it's done the prompt will be replaced with:
```
>>>
```
From here you can chat with the LLM!

View file

@ -2,7 +2,7 @@
title: "Polymorphic Functions w/ Wildcard Matching in Lean 4" title: "Polymorphic Functions w/ Wildcard Matching in Lean 4"
date: 2024-08-04T07:21:07-07:00 date: 2024-08-04T07:21:07-07:00
draft: false draft: false
tags: ["Formal Methods"] tags: []
math: false math: false
medium_enabled: false medium_enabled: false
--- ---

View file

@ -1,94 +0,0 @@
---
title: "Is this program safe? Lessons from Type Theory"
date: 2025-05-10T09:28:07-04:00
draft: false
tags: []
math: true
medium_enabled: false
---
*This blog post is inspired from a lecture that Dr. Ana Milanova gave in her Principles of Program Analysis course.*
Consider an arbitrary computer program. When we execute it, we expect that it will produce some result and not get *stuck*.
For example,
```python
id = lambda x: x
id 5
```
In the code above, we create an identity function `id` which takes an argument `x` and returns that same argument. Therefore, in the second line when we call the function with the value `5`, we receive the value `5` as a result.
Now what about the following?
```python
5 id
```
This program does not make any sense since the value `5` is not a function and hence does not take anything as an argument. Ideally, we want to catch errors like these before we run our code. In fact, we can by relying on a *type checker*.
Through this, we only execute programs that have a valid *type*. If not, then we say that the program is invalid.
- `id 5` is of type `int`
- `5 id` does not have a valid type
We won't delve into the formal theory of type systems, however, know that we can design a type system to be as complicated as we'd like. We can even go as far as verifying whether the result equals an expected value at the end of program execution. However, the [Halting problem](https://en.wikipedia.org/wiki/Halting_problem) from theoretical computer science tells us that we cannot write an algorithm that's guaranteed to eventually end and tell us whether an inputted program will return a specific result.
Due to this, we need to make some compromises in type checkers. We really want it so that if a program passes the type checker, then it will never get stuck during execution by encountering something like `5 id`. Therefore, instead we compromise by failing programs that will actually never get stuck.
*Designing a type system is a trade off between runtime and how many valid programs we are able to call type safe.*
In other words, there will be programs that are valid and produce a result, however our type system will not accept it.
{{<unsafe>}}
<img alt="Venn Diagram showing that type accepted programs are smaller and within the space of valid programs" src="/files/images/blog/type-safety-venn.svg" width="500px"/>
{{</unsafe>}}
For example, let us consider one of the simplest type systems. That is the simply typed lambda calculus. We won't go into the formal details of its presentation, but instead highlight how it won't allow all valid programs through an example.
```python
id = lambda x : x
if (id true) then (id 5) else (id 6)
```
Consider again our identity function but this time it is used within an if-then-else (ite) expression. When we run this code, it will return the value `5` which is of type `int`. However, what does the type checker think?
In the simply typed lambda calculus, the type of an expression may either be a base type like an `int` or ` bool`, or it can be a function type which takes a type and returns a type (i.e,`type` $\rightarrow$ `type`).
From the definition of `id`, we cannot determine what type it has. Instead we know that for some type variable $t$, it is $t \rightarrow t$.
Then, we take a look at the conditional part of the ite expression. We derive that `id` must have type `bool` $\rightarrow$ `bool`. However, the other two parts of the ite expression requires that `id` takes and returns an `int`!
Since `bool` and `int` are two distinct types, a type checker based on the simply typed lambda calculus will not accept this program.
In order for our type checker to accept this program, the underlying type system must support polymorphic types (sometimes called polytypes). An example system that does is System F.
The biggest difference during type inference, is that instead of determining that `id` has type $t \rightarrow t$ for some type variable $t$. It has type $\forall t, t \rightarrow t$. Thus, allowing for both an identity function that takes a `bool` and returns a `bool`, and for an identity function to take an `int` and return an `int`.
Even with polytypes, our type checker will still not accept all valid programs! A great overview on the different dimensions of type systems is on the Wikipedia page for [Lambda Cube](https://en.wikipedia.org/wiki/Lambda_cube).
In our examples above, we had our type checker also perform inference to identify what the type of the expressions are. However, we can use more efficient algorithms if we forced the writer of the program to annotate the types instead. This is another trade off to think about when designing a programming language.
{{<unsafe>}}
<img alt="Venn Diagram showing that simply type accepted programs are smaller and within system f accepted programs which are within space of valid programs" src="/files/images/blog/type-safety-simply-systemf-venn.svg" width="500px"/>
{{</unsafe>}}
Or, we can throw all caution to the wind and have our program crash and throw exceptions instead.
Example in Python:
```python
5 (lambda x: x)
```
```
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
```

View file

@ -1,79 +0,0 @@
---
title: "Quick Lean: if-then-else statement in hypothesis"
date: 2025-04-26T10:58:42-04:00
draft: false
tags: ["Formal Methods"]
math: false
medium_enabled: false
---
When verifying proofs about code, I often end up with a hypothesis that has an if statement in it. Depending on how long it's been since I last used Lean, I forget how to deal with it. This is a quick post to remind me how.
Example:
```lean
example (b: Bool) (n: Nat) (H1: if b then (n = 5) else (n = 3)) : n > 0 := by sorry
```
We want to show that for an arbitrary boolean and natural number `n`, that `n` will always be greater than zero.
Note that the condition of an arbitrary if statement can take a proposition instead of a boolean. However for this to work the proposition must be *decidable*. Checking the condition of a boolean is decidable, so we'll use that to simplify our example.
From here, we use `by_cases (b = true)` to give us two new subgoals. One where it's true and one where it's false.
```lean
by_cases H2 : (b = true)
case pos =>
sorry
case neg =>
sorry
```
First let's consider the positive case. We can simplify `H1` to `n = 5` by using `H2` which states that `b` is true.
```lean
replace H1 : n = 5 := by
rwa [if_pos (by exact H2)] at H1
```
For this example, you don't need the parenthesis saying `(by exact H2)`. However, depending on your setup the proof that `b` is true might be too difficult for the rewrite system to infer. In those cases, you are required to specify the proof for it to work.
Then, we can substitute `n` to have our subgoal as `5 > 0`.
```lean
subst n
```
This is the same as showing that `0 < 5`.
```lean
suffices 0 < 5 by exact gt_iff_lt.mpr this
```
From here we can apply one of the builtin theorems
```lean
exact Nat.zero_lt_succ 4
```
For the negative case, we will follow a similar pattern except instead of invoking `if_pos` to eliminate the if-statement, we will invoke `if_neg`.
Thus, the complete proof for this is
```lean
example (b : Bool) (n : Nat) (H1: if b then (n = 5) else (n = 3)) : n > 0 := by
by_cases H2 : (b = true)
case pos =>
replace H1 : n = 5 := by
rwa [if_pos (by exact H2)] at H1
subst n
suffices 0 < 5 by exact gt_iff_lt.mpr this
exact Nat.zero_lt_succ 4
case neg =>
replace H1 : n = 3 := by
rwa [if_neg (by exact H2)] at H1
subst n
suffices 0 < 3 by exact gt_iff_lt.mpr this
exact Nat.zero_lt_succ 2
```

View file

@ -1,17 +0,0 @@
---
title: "Recently (June 2024)"
date: 2024-06-15T21:21:22-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
**Professional:** I'm well into the PhD program at this point. I've been fortunate enough to receive the NDSEG fellowship which funds my work, as well as many wonderful collaborators.
This summer, I'm an applied scientist intern at Amazon Web Services. I work on the [Cedar project](https://www.cedarpolicy.com/) which is under Automated Reasoning in Identities. I'm especially excited at the oppurtunity to write Lean code.
**Personal Life:** For the internship, I moved out to San Jose, California. The biggest surprise to me is just how blue the sky is almost every day!
There's a lot to explore here. I'm making edits on [OpenStreetMap](https://www.openstreetmap.org/user/Brandon%20Rozek/) using the Street Complete application on Android along the way.

View file

@ -1,103 +0,0 @@
---
title: "Recently: April Showers Bring..."
date: 2025-04-12T10:38:45-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
I woke up this morning to a small layer of snow outside. In the Northeastern part of the United States, it's said that we have [12 seasons](https://12seasons.nyc/).
- Winter
- Fool's Spring
- Second Winter
- Spring of Deception
- Third Winter
- The Pollening
- Actual Spring
- Summer
- Hell's Front Porch
- False Fall
- Second Summer
- Actual Fall
At the time of this post, we're at "Third Winter". I look forward to warm weather again soon.
---
*Homelab Updates!*
**Nextcloud:** I moved away from the Nextcloud all-in-one and instead maintain a LXC container. Unfortunately for me, the all-in-one was too much of a black box. My current deployment is significantly less stateless, but I understand it better.
While I was doing that, I've been exploring use-cases for MinIO so I thought maybe I'll try [configuring my object storage as the primary storage](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/primary_storage.html). However, I neglected to read the third paragraph...
> All metadata (filenames, directory structures, etc) is stored in Nextcloud and not in the object store
This makes performing backups significantly harder! So, I switched back to the normal filesystem backend for Nextcloud.
**Immich:** Multiple people have told me that Immich is the way to go for viewing your photos. Previously, I was scared to try it out because of the banner at the top of their page.
> The project is under **very active** development. Expect bugs and changes. Do not use it as **the only way** to store your photos and videos.
However, I have backups so what am I afraid of?
I have to say, the setup was flawless. The software is not buggy at all, and everything is snappy and works as expected.
To import my photos, I mounted my existing directory on a *different* mountpoint than the one Immich uses to store files.
Example Docker-Compose Configuration
```yaml
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:release
env_file:
- /etc/immich/immich.env
volumes:
- /home/user/immich/pictures:/usr/src/app/upload
- /home/user/storage/pictures:/pictures:ro # Existing photo library
- /etc/localtime:/etc/localtime:ro
depends_on:
- immich-redis
- immich-database
restart: unless-stopped
# Copy immich-redis and immich-database from the Github repo
# ...
```
Then I had to log onto the Immich webapp to create a user and an API key. After that, we can `exec` into the container.
```bash
docker exec -it immich_server /bin/bash
```
Login with the API key
```bash
immich login http://localhost:2283/api <APIKEY>
```
Then upload the photos
```bash
immich upload --recursive /pictures
```
*Warning:* You need enough space to have two copies of your photos. If you don't then you'll need to iteratively upload and delete as you go instead of doing this all at once.
After a bit, you should see thumbnails on the app!
**Music Streaming:** Since I listen to Japanese music, not all music services work for me. Currently I pay for YT Music, though I've been slowly trying to buy albums directly from Qobuz to (1) better support the artists, and (2) guarantee that it won't disappear from my library. This is only recent, so I don't fully endorse my workflow, but it's been working so far and I think it's great.
1. Buy flac from [Qobuz](https://www.qobuz.com/us-en/shop)
2. Transfer the files to my home server
3. Run [`beet import`](https://beets.io/) to copy the music into my library with all the metadata sorted out.
4. Use [Navidrome](https://www.navidrome.org/), an open-source server software, to provide a subsonic API to stream the music.
- It even transcodes on the fly for you if your device doesn't support the format it's stored in.
5. Use [Symfonium](https://symfonium.app/) on Android as my music app and set it to search for music on my Navidrome server.
Both Immich and setting up this music streaming is very new to me! So if you have any suggestions or comments about your workflow feel free to reach out :)

View file

@ -22,7 +22,7 @@ Quick option definitions (from man page)
| Option | Description | | Option | Description |
| -------------- | ------------------------------------------------------------ | | -------------- | ------------------------------------------------------------ |
| -e | Allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name. | | -e | Allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name. |
| -a, --archive | This is equivalent to -rlptgoD. It is a quick way of saying you want recursion and want to preserve almost everything (with -H being a notable omission). The only exception to the above equivalence is when --files-from is specified, in which case -r is not implied. Note that -a does not preserve hardlinks, because finding multiply-linked files is expensive. You must separately specify -H. | | -a, --archive | This is equivalent to -rlptgoD. It is a quick way of saying you want recursion and want to preserve almost everything (with -H being a notable omission). The only exception to the above equivalence is when --files-from is specified, in which case -r is not implied. <br />Note that -a does not preserve hardlinks, because finding multiply-linked files is expensive. You must separately specify -H. |
| -P | Equivalent to --partial --progress. Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted. | | -P | Equivalent to --partial --progress. Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted. |
| -z, --compress | Compress file data during the transfer | | -z, --compress | Compress file data during the transfer |
| --delete | Delete extraneous files from dest dirs | | --delete | Delete extraneous files from dest dirs |

View file

@ -58,20 +58,16 @@ Please select what kind of key you want:
(4) RSA (sign only) (4) RSA (sign only)
(5) Elgamal (encrypt only) (5) Elgamal (encrypt only)
(6) RSA (encrypt only) (6) RSA (encrypt only)
(10) ECC (sign only)
(12) ECC (encrypt only)
(14) Existing key from card (14) Existing key from card
Your selection? Your selection?
``` ```
As before, I recommend going with the default signing key option. As before, I recommend going with the default signing key option.
I recently chose `(10) ECC (sign only)`. In this case it's `(3) DSA (sign only)`.
``` ```
Please select which elliptic curve you want: DSA keys may be between 1024 and 3072 bits long.
(1) Curve 25519 *default* What keysize do you want? (2048)
(4) NIST P-384
(6) Brainpool P-256
``` ```
As before, either stick with the default or tweak based As before, either stick with the default or tweak based
@ -96,7 +92,7 @@ sec rsa3072/3E40C8DB05FCCFAD
trust: ultimate validity: ultimate trust: ultimate validity: ultimate
ssb rsa3072/50CC6B37C26F7882 ssb rsa3072/50CC6B37C26F7882
created: 2022-12-18 expires: 2023-12-18 usage: E created: 2022-12-18 expires: 2023-12-18 usage: E
ssb ed25519/5C1B6FCA0DABB046 ssb dsa2048/5C1B6FCA0DABB046
created: 2022-12-18 expires: 2023-12-18 usage: S created: 2022-12-18 expires: 2023-12-18 usage: S
[ultimate] (1). TestKey [ultimate] (1). TestKey
``` ```

View file

@ -9,18 +9,18 @@ medium_enabled: false
A lot of software nowadays are built for scale. You have to setup a Kubernetes cluster and deploy Redis for duplication in order to have a key-value store. Though for many small projects, I feel like it's overkill. A lot of software nowadays are built for scale. You have to setup a Kubernetes cluster and deploy Redis for duplication in order to have a key-value store. Though for many small projects, I feel like it's overkill.
I'll show in this post, that we can have a nice simple[^1] key-value store using `sqlite3`[^2]. This gives us the benefit that we don't need to use system resources to run a daemon the entire time and only spin up a process when we need it. I'll show in this post, that we can have a nice simple[^1] key-value store using `sqlite3`. This gives us the benefit that we don't need to use system resources to run a daemon the entire time and only spin up a process when we need it.
For our key-value store, we're going to use a table with two columns: For our key-value store, we're going to use a table with two columns:
- A key, which we'll call `name`. This will be a unique `TEXT` type that has to be set. - A key, which we'll call `name`. This will be a unique `TEXT` type that has to be set.
- The value, which we'll call `value` (Creative, I know.) For our purposes, this will also be a `TEXT` type. - The value, which we'll call `value` (Creative, I know.) For our purposes, this will also be a `TEXT` type.
The SQL to create this table is[^3] The SQL to create this table is[^2]
```sql ```sql
CREATE TABLE config( CREATE TABLE config(
name TEXT NOT NULL, name TEXT PRIMARY KEY,
value TEXT value TEXT
); );
``` ```
@ -123,6 +123,5 @@ $ ./sqlite3_getkv.sh test.db a
``` ```
[^1]: Somehow my idea of easier, simpler, and more maintainable is writing bash scripts. [^1]: Somehow my idea of easier, simpler, and more maintainable is writing bash scripts.
[^2]: Justin pointed out that the [CPython implementation](https://github.com/python/cpython/blob/a15a584bf3f94ea11ab9363548c8872251364000/Lib/dbm/sqlite3.py#L7) works similarly. [^2]: Thanks Justin for helping me simplify it from `NOT NULL UNIQUE` to `PRIMARY KEY`.
[^3]: Unfortantely, we can't only use the `PRIMARY KEY` qualifier for the name field as sqlite has a [historical quirk](https://www.sqlite.org/quirks.html) which allows primary keys to be null.

View file

@ -9,7 +9,7 @@ Part of my job involves integrating multiple different sensors together to make
Now since we're working with sensor data, it doesn't always make sense to need to be connected to a whole system. There's also the additional hassle of dealing with safety and working outside. So in order to do some programming and still be at ease that we didn't break anything, we make heavy use of simulators. Now since we're working with sensor data, it doesn't always make sense to need to be connected to a whole system. There's also the additional hassle of dealing with safety and working outside. So in order to do some programming and still be at ease that we didn't break anything, we make heavy use of simulators.
**Example**: Have a GPS hooked up to your system? Well with a tool you can make waypoints and generate a file which you then feed in as a fake GPS device! <u>Example</u>: Have a GPS hooked up to your system? Well with a tool you can make waypoints and generate a file which you then feed in as a fake GPS device!
Now when I say fake device, I don't mean I'm actually emulating the device on the machine. It's easier to have your device interfacers publish to the local network and have your other parts of the application subscribe to it. So in this case, you will just need to produce those messages directly. Now when I say fake device, I don't mean I'm actually emulating the device on the machine. It's easier to have your device interfacers publish to the local network and have your other parts of the application subscribe to it. So in this case, you will just need to produce those messages directly.

View file

@ -18,7 +18,7 @@ ControlPath ~/.ssh/sockets/socket-%r@%h:%p
| Option | Description | | Option | Description |
| ---------------- | ------------------------------------------------------------ | | ---------------- | ------------------------------------------------------------ |
| `ControlMaster` | Allows connection sharing | | `ControlMaster` | Allows connection sharing |
| `ControlPersist` | `yes` to keep connection up even when no clients are connected. `2s` (or custom timeout) to keep the connection up for 2 seconds after no clients are connected.`no` to disconnect immediately | | `ControlPersist` | `yes` to keep connection up even when no clients are connected.<br />`2s` (or custom timeout) to keep the connection up for 2 seconds after no clients are connected.<br />`no` to disconnect immediately |
| `ControlPath` | Where to store connection information. This should not be writable by other users. | | `ControlPath` | Where to store connection information. This should not be writable by other users. |

View file

@ -49,7 +49,7 @@ medium_enabled: false
"icon": "{{ .Site.BaseURL }}img/{{ .Site.Params.avatar }}", "icon": "{{ .Site.BaseURL }}img/{{ .Site.Params.avatar }}",
"language": "en-US", "language": "en-US",
"authors": [ "authors": [
{{with $.Site.Params.name }} {{with $.Site.Author.name }}
{ "name": "{{ . }}" } { "name": "{{ . }}" }
{{ end }} {{ end }}
], ],
@ -71,7 +71,7 @@ My `list.json.json` follows the [JSON Feed](https://jsonfeed.org/) specification
"url": "{{ .Permalink }}", "url": "{{ .Permalink }}",
"title": {{ .Title | jsonify }}, "title": {{ .Title | jsonify }},
"authors": [ "authors": [
{{with $.Site.Params.Author }} {{with $.Site.Author.name }}
{ "name": "{{ . }}" } { "name": "{{ . }}" }
{{ end }} {{ end }}
], ],

View file

@ -1,109 +0,0 @@
---
title: "Temporary Port Forward using UPnP in Linux"
date: 2024-12-08T21:04:51-05:00
draft: false
tags: []
math: false
medium_enabled: false
---
I don't know about you, but I don't particularly enjoy logging onto my router. *Especially since the web UI differs between router models.* Unfortunately, a common step of hosting a multiplayer game server at home is to set up a port forward.
This tells your router to take traffic coming in at a specified external *port*, and *forward* it to one of your computer's internal IP address at a specified local port.
![Port Forward Diagram](/files/images/blog/PortForward.svg)
What if I tell you that instead of having to login to your router interface every time you want to set up a port forward, you can programatically perform it from your Linux machine? This is where Universal Plug and Play (UPnP) comes in. Some games even automatically manage this for you!
Since router configurations vary widely, we'll assume that you already have UPnP enabled. Not all routers, however, support this. Look up the model of your router with UPnP to see if yours does. For example, [here's how to set it up within pfSense](https://docs.netgate.com/pfsense/en/latest/services/upnp.html).
Enabling UPnP by default means allowing any computer in your network to modify port forwarding. For security reasons, you'll likely want to restrict this to a few trusted machines, i.e. game consoles and laptops.
In order to manage UPnP from a Linux machine, we'll need the `upnpc` command. This can be found in the `miniupnpc` package on Fedora.
```bash
sudo dnf install miniupnpc
```
From here, we can check if we've enabled UPnP by querying for its status
```bash
upnpc -s
```
If it returns the following, then UPnP is not properly set up!
```
No IGD UPnP Device found on the network !
```
Otherwise you'll get a lot of information including:
```
Found valid IGD : <REDACTED URL>
```
Assuming everything is setup correctly, we'll run through an example. Say that we want to run a Starbound server. This typically runs on port `21025`.
```bash
export INTERNAL_PORT=21025
```
We'll need to know our computer's internal IP address. Assuming that `1.0.0.0` will take you to the Internet and not some virtual private network, we can run the following to get our internal IP address
```bash
export INTERNAL_IP=$(ip route get 1 | awk '{print $7}')
```
For the external port that our friends will connect to, we'll need to pick an arbitrarily high number that's not already assigned. This number can be between 1024-65535 depending on your UPnP configuration.
For example,
```bash
export EXTERNAL_PORT=60821
```
Lastly, we need to know whether our game server accepts TCP or UDP requests. Starbounds expects TCP requests.
```bash
export PROTOCOL=TCP
```
Now we can issue a command to our router using `upnpc` to forward traffic on the external port to our local computer at the specified internal port.
```bash
upnpc -a $INTERNAL_IP $INTERNAL_PORT $EXTERNAL_PORT $PROTOCOL
```
From here, people outside of your network should be able to send traffic to your local computer! They'll need to know your external IP address.
```bash
upnpc -s | grep Ext
```
If your friends are having trouble connecting to your external IP address and port, double check that your local computer's firewall isn't blocking the traffic and check the UPnP routing list.
```bash
upnpc -l
```
When you're done, don't forget to delete the rule from UPnP.
```bash
upnpc -d $EXTERNAL_PORT $PROTOCOL
```
Other than gaming, another use case for this is file transfer. Say you want to receive a file from a friend. To not repeat details, assume we're using the same variables from above and you already added the port forward to UPnP.
On your local machine, use `netcat` to listen for traffic and write the bytes received to a file.
```bash
nc -l $INTERNAL_PORT > file_received.txt
```
Your friend can now send you a file.
```bash
nc $EXTERNAL_IP $EXTERNAL_PORT < file_to_send.txt
```

View file

@ -1,132 +0,0 @@
---
title: "Verifying Proofs with Type Checkers"
date: 2025-05-27T09:27:59-04:00
draft: false
tags: ["Formal Methods"]
math: true
medium_enabled: false
---
The [Curry-Howard Correspondance](https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence) establishes a direct connection between computer programs and mathematical proofs.
| Programs | Proofs |
| ----------------------------- | ----------------------- |
| Type | Formula |
| Term | Proof |
| Type has an element | Formula is provable |
| Type does not have an element | Formula is not provable |
When we think about traditional type systems, however, most are uncapable of expressing interesting formula. This ultimately limits the formulas we can prove.
For example, consider the simply typed lambda calculus. In that system we have base types like `int` and `bool`, as well as function types $t1 \rightarrow t2$ which take a type and return a type.
From that system, we can then create a proof of an integer by showing the term `0`. The following shows how to use the Lean 4 type checker to verify that `0` is an integer:
```lean4
#check (0: Int)
```
This, however, isn't a very interesting proof or formula. What would be more interesting is if we can use a type checker to verify the following:
```lean4
#check (by exists [] : ∃ (x : List Int), x.length = 0)
```
Sadly, we can't verify this with the simply typed lambda calculus. This does not mean that we cannot design a type system that can.
Interactive theorem provers (ITPs) or [proof assistants](https://en.wikipedia.org/wiki/Proof_assistant) help fill this void. Equipped with sophisticated type systems, they allow us to prove a formula by writing a program of that type. Some of the most popular ones include [Lean](https://lean-lang.org/), [Rocq](https://rocq-prover.org/), [Isabelle](https://isabelle.in.tum.de/), [Agda](https://wiki.portal.chalmers.se/agda/pmwiki.php), and [F*](https://fstar-lang.org/).
The underlying type system of each proof assistant is different. However, there are many similarities. In general, most aim to be at least as powerful as the calculus of constructions developed by Thierry Coquand.
To get an idea of how expressive these type systems are, we can analyze the [Lambda cube](https://en.wikipedia.org/wiki/Lambda_cube). Developed by Henk Barendregt, this characterizes the space between the simply typed lambda calculus and the calculus of constructions.
![](/files/images/blog/Lambda_Cube_img.svg)
[Image courtesy of Tellofou on Wikipedia](https://commons.wikimedia.org/wiki/File:Lambda_Cube_img.svg).
Each dimension corresponds to an extension of the simply typed lambda calculus:
- X Axis: Dependent types (Types that depend on terms)
- Y Axis: Polymorphic types (Terms that depend on types)
- Z Axis: Type Operators (Types that depend on types)
**Dependent Type**
A dependent type is a type that depends on some term. We can use this to, for example, write functions that return entirely different base types depending on the outcome of some conditional.
Here's an example function you can write in Lean 4:
```lean4
def isZeroOrMore (n : Nat) : (if n == 0 then Bool else Nat) :=
if H: n == 0 then by
rw [if_pos (by exact H)]
exact true
else by
rw [if_neg (by exact H)]
exact n
```
The function `isZeroOrMore` will return `true` if the parameter `n` is equal to zero, otherwise it'll return the natural number parameter itself.
**Type Operators**
A type operator takes a type and produces a type. For example, we can create a triple type that represents the product of three base types.
```lean4
structure Triple {A B C : Type} where
a: A
b: B
c: C
```
Let's say that we want to enforce that all three elements of the triple are of type `Int`. Then we can create a new type `IntTriple` as follows:
```Lean 4
def IntTriple := @Triple Int Int Int
```
From here, we can use `IntTriple` when type checking values.
```
#check (Triple.mk 1 2 3 : IntTriple)
````
**Type Polymorphism**
Type polymorphism allows us to write one function which covers many different types. There are two common places that we see this often.
Identity function:
```lean4
def iden {α : Type} (x : α) : α := x
```
Here we're saying that the parameter a can be of any arbitrary type α, and the function `iden` will then just return the parameter itself.
We also see this often when defining operations over lists
```lean4
def map {α β : Type} (f: α → β) (as: List α): List β :=
match as with
| [] => []
| (head::tail) => f head :: map f tail
```
The calculus of constructions support all of these three extensions. We've introduced enough here to write a more interesting proof.
```lean4
theorem map_iden_idempotent {α : Type} (as: List α) : (map iden as = as) := by
unfold iden
induction as
case nil =>
unfold map
rfl
case cons h t IH =>
unfold map
rw [IH]
```
We've invoked the Lean type checker to verify that for a list of any arbitrary type, when you map over it with the identity function you get back the list itself.
You might ask, why don't all programming languages support this? By adding expressivity to our type system, we sacrifice computational efficiency. For most standard programming tasks, we want our type checker to be as fast as possible. However when we require stronger guarentees of correctness about our code, proof assistants are a great tool for the job. Many of them even generate code for mainstream programming languages.
That's all for today. I'd like to thank James Oswald for the inspiration to write this post and some of its examples. This was adapted from a presentation we gave last month to our weekly seminar series.

View file

@ -14,7 +14,7 @@ First of all, I wanted to include a video of a bot playing Pong. The video was a
You just need to replace the `0.1` with the appropriate decimal number to change the speed. You just need to replace the `0.1` with the appropriate decimal number to change the speed.
Giphy has a great [writeup](https://web.archive.org/web/20200109095206/https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/) describing the commands to use in order to make your GIF look nice. Giphy has a great [writeup](https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/) describing the commands to use in order to make your GIF look nice.
```bash ```bash
ffmpeg -i inputvideo.mp4 -filter_complex "[0:v] palettegen" palette.png ffmpeg -i inputvideo.mp4 -filter_complex "[0:v] palettegen" palette.png

View file

@ -1,556 +0,0 @@
---
title: "Weather Forcecasts on the Command-Line with the National Weather Service API"
date: 2025-03-16T15:33:49-04:00
draft: false
tags: []
math: false
medium_enabled: false
---
The United States National Weather Service (NWS) has a [JSON API](https://www.weather.gov/documentation/services-web-api) which provides weather alerts and forecasts for free without having to create an API key[^1]. We'll use this resource to write a small bash script which gives today and tomorrow's weather forecast given a latitude and longitude.
[^1]: In this day and age, it almost feels too good to be true.
My goal is to have a small bash script which I can run in the terminal to get the forecast information. We'll use [`jq`](https://jqlang.org/) for handling the JSON data.
The NWS API does not provide the forecast directly given a latitude and longitude coordinates. Instead, we need to provide the specific [Weather Forecast Office (WFO)](https://www.weather.gov/srh/nwsoffices) responsible for that area plus their grid definitions for the latitude and longitude coordinate.
Luckily, we can query for that information as well.
```bash
POINTS=$(curl -Ls "https://api.weather.gov/points/$LAT,$LON")
```
{{< unsafe >}}<details><summary>For 42.7289, -73.6915 it returns:</summary>{{</unsafe >}}
```json
{
"@context": [
"https://geojson.org/geojson-ld/geojson-context.jsonld",
{
"@version": "1.1",
"wx": "https://api.weather.gov/ontology#",
"s": "https://schema.org/",
"geo": "http://www.opengis.net/ont/geosparql#",
"unit": "http://codes.wmo.int/common/unit/",
"@vocab": "https://api.weather.gov/ontology#",
"geometry": {
"@id": "s:GeoCoordinates",
"@type": "geo:wktLiteral"
},
"city": "s:addressLocality",
"state": "s:addressRegion",
"distance": {
"@id": "s:Distance",
"@type": "s:QuantitativeValue"
},
"bearing": {
"@type": "s:QuantitativeValue"
},
"value": {
"@id": "s:value"
},
"unitCode": {
"@id": "s:unitCode",
"@type": "@id"
},
"forecastOffice": {
"@type": "@id"
},
"forecastGridData": {
"@type": "@id"
},
"publicZone": {
"@type": "@id"
},
"county": {
"@type": "@id"
}
}
],
"id": "https://api.weather.gov/points/42.7289,-73.6915",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-73.6915,
42.7289
]
},
"properties": {
"@id": "https://api.weather.gov/points/42.7289,-73.6915",
"@type": "wx:Point",
"cwa": "ALY",
"forecastOffice": "https://api.weather.gov/offices/ALY",
"gridId": "ALY",
"gridX": 74,
"gridY": 67,
"forecast": "https://api.weather.gov/gridpoints/ALY/74,67/forecast",
"forecastHourly": "https://api.weather.gov/gridpoints/ALY/74,67/forecast/hourly",
"forecastGridData": "https://api.weather.gov/gridpoints/ALY/74,67",
"observationStations": "https://api.weather.gov/gridpoints/ALY/74,67/stations",
"relativeLocation": {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-73.707011,
42.724883
]
},
"properties": {
"city": "Watervliet",
"state": "NY",
"distance": {
"unitCode": "wmoUnit:m",
"value": 1343.4228258697
},
"bearing": {
"unitCode": "wmoUnit:degree_(angle)",
"value": 70
}
}
},
"forecastZone": "https://api.weather.gov/zones/forecast/NYZ053",
"county": "https://api.weather.gov/zones/county/NYC083",
"fireWeatherZone": "https://api.weather.gov/zones/fire/NYZ208",
"timeZone": "America/New_York",
"radarStation": "KENX"
}
}
```
{{< unsafe >}}</details><br/>{{</unsafe >}}
That's a lot of output! However, we only need three pieces of information:
- WFO office (ex: "ALY")
- Grid-X (ex: 74)
- Grid-Y (ex: 67)
We can use the following code to store this into variables using `jq`
```bash
OFFICE=$(echo $POINTS | jq -r .properties.gridId)
X=$(echo $POINTS | jq .properties.gridX)
Y=$(echo $POINTS | jq .properties.gridY)
```
From here, we can query for the weather forecast for that grid point.
```bash
WEATHER=$(curl -Ls "https://api.weather.gov/gridpoints/$OFFICE/$X,$Y/forecast")
```
{{< unsafe >}}<details><summary>Show output:</summary>{{</unsafe >}}
```json
{
"@context": [
"https://geojson.org/geojson-ld/geojson-context.jsonld",
{
"@version": "1.1",
"wx": "https://api.weather.gov/ontology#",
"geo": "http://www.opengis.net/ont/geosparql#",
"unit": "http://codes.wmo.int/common/unit/",
"@vocab": "https://api.weather.gov/ontology#"
}
],
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.6648,
42.7172
],
[
-73.6602,
42.7386
],
[
-73.6893,
42.742
],
[
-73.694,
42.720499999999994
],
[
-73.6648,
42.7172
]
]
]
},
"properties": {
"units": "us",
"forecastGenerator": "BaselineForecastGenerator",
"generatedAt": "2025-03-16T19:59:48+00:00",
"updateTime": "2025-03-16T19:38:29+00:00",
"validTimes": "2025-03-16T13:00:00+00:00/P8D",
"elevation": {
"unitCode": "wmoUnit:m",
"value": 61.8744
},
"periods": [
{
"number": 1,
"name": "This Afternoon",
"startTime": "2025-03-16T15:00:00-04:00",
"endTime": "2025-03-16T18:00:00-04:00",
"isDaytime": true,
"temperature": 69,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "22 mph",
"windDirection": "S",
"icon": "https://api.weather.gov/icons/land/day/wind_ovc?size=medium",
"shortForecast": "Cloudy",
"detailedForecast": "Cloudy, with a high near 69. South wind around 22 mph, with gusts as high as 43 mph. New rainfall amounts less than a tenth of an inch possible."
},
{
"number": 2,
"name": "Tonight",
"startTime": "2025-03-16T18:00:00-04:00",
"endTime": "2025-03-17T06:00:00-04:00",
"isDaytime": false,
"temperature": 50,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 100
},
"windSpeed": "5 to 21 mph",
"windDirection": "SW",
"icon": "https://api.weather.gov/icons/land/night/tsra,100?size=medium",
"shortForecast": "Showers And Thunderstorms",
"detailedForecast": "A chance of rain showers before 8pm, then showers and thunderstorms. Cloudy, with a low around 50. Southwest wind 5 to 21 mph, with gusts as high as 44 mph. Chance of precipitation is 100%. New rainfall amounts between three quarters and one inch possible."
},
{
"number": 3,
"name": "Monday",
"startTime": "2025-03-17T06:00:00-04:00",
"endTime": "2025-03-17T18:00:00-04:00",
"isDaytime": true,
"temperature": 53,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 60
},
"windSpeed": "5 to 12 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/day/rain_showers,60/rain_showers,50?size=medium",
"shortForecast": "Rain Showers Likely",
"detailedForecast": "Rain showers likely. Cloudy. High near 53, with temperatures falling to around 46 in the afternoon. Northwest wind 5 to 12 mph. Chance of precipitation is 60%. New rainfall amounts between a half and three quarters of an inch possible."
},
{
"number": 4,
"name": "Monday Night",
"startTime": "2025-03-17T18:00:00-04:00",
"endTime": "2025-03-18T06:00:00-04:00",
"isDaytime": false,
"temperature": 31,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 30
},
"windSpeed": "7 to 10 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/night/rain_showers,30/bkn?size=medium",
"shortForecast": "Chance Rain Showers then Mostly Cloudy",
"detailedForecast": "A chance of rain showers before 8pm. Mostly cloudy, with a low around 31. Northwest wind 7 to 10 mph. Chance of precipitation is 30%. New rainfall amounts between a tenth and quarter of an inch possible."
},
{
"number": 5,
"name": "Tuesday",
"startTime": "2025-03-18T06:00:00-04:00",
"endTime": "2025-03-18T18:00:00-04:00",
"isDaytime": true,
"temperature": 56,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "7 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/day/few?size=medium",
"shortForecast": "Sunny",
"detailedForecast": "Sunny, with a high near 56. Northwest wind around 7 mph."
},
{
"number": 6,
"name": "Tuesday Night",
"startTime": "2025-03-18T18:00:00-04:00",
"endTime": "2025-03-19T06:00:00-04:00",
"isDaytime": false,
"temperature": 35,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "1 to 5 mph",
"windDirection": "NE",
"icon": "https://api.weather.gov/icons/land/night/few?size=medium",
"shortForecast": "Mostly Clear",
"detailedForecast": "Mostly clear, with a low around 35."
},
{
"number": 7,
"name": "Wednesday",
"startTime": "2025-03-19T06:00:00-04:00",
"endTime": "2025-03-19T18:00:00-04:00",
"isDaytime": true,
"temperature": 65,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "2 to 9 mph",
"windDirection": "SE",
"icon": "https://api.weather.gov/icons/land/day/sct?size=medium",
"shortForecast": "Mostly Sunny",
"detailedForecast": "Mostly sunny, with a high near 65."
},
{
"number": 8,
"name": "Wednesday Night",
"startTime": "2025-03-19T18:00:00-04:00",
"endTime": "2025-03-20T06:00:00-04:00",
"isDaytime": false,
"temperature": 45,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "9 mph",
"windDirection": "SE",
"icon": "https://api.weather.gov/icons/land/night/bkn?size=medium",
"shortForecast": "Mostly Cloudy",
"detailedForecast": "Mostly cloudy, with a low around 45."
},
{
"number": 9,
"name": "Thursday",
"startTime": "2025-03-20T06:00:00-04:00",
"endTime": "2025-03-20T18:00:00-04:00",
"isDaytime": true,
"temperature": 61,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 50
},
"windSpeed": "8 to 14 mph",
"windDirection": "S",
"icon": "https://api.weather.gov/icons/land/day/bkn/rain_showers,50?size=medium",
"shortForecast": "Mostly Cloudy then Chance Rain Showers",
"detailedForecast": "A chance of rain showers after 2pm. Mostly cloudy, with a high near 61. Chance of precipitation is 50%."
},
{
"number": 10,
"name": "Thursday Night",
"startTime": "2025-03-20T18:00:00-04:00",
"endTime": "2025-03-21T06:00:00-04:00",
"isDaytime": false,
"temperature": 33,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 70
},
"windSpeed": "8 to 12 mph",
"windDirection": "SW",
"icon": "https://api.weather.gov/icons/land/night/rain_showers,70/snow,70?size=medium",
"shortForecast": "Rain Showers Likely then Chance Rain And Snow Showers",
"detailedForecast": "Rain showers likely before 2am, then a chance of rain and snow showers. Mostly cloudy, with a low around 33. Chance of precipitation is 70%."
},
{
"number": 11,
"name": "Friday",
"startTime": "2025-03-21T06:00:00-04:00",
"endTime": "2025-03-21T18:00:00-04:00",
"isDaytime": true,
"temperature": 41,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 50
},
"windSpeed": "12 to 17 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/day/snow,50/snow,30?size=medium",
"shortForecast": "Chance Rain And Snow Showers",
"detailedForecast": "A chance of rain and snow showers. Partly sunny, with a high near 41. Chance of precipitation is 50%."
},
{
"number": 12,
"name": "Friday Night",
"startTime": "2025-03-21T18:00:00-04:00",
"endTime": "2025-03-22T06:00:00-04:00",
"isDaytime": false,
"temperature": 30,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "9 to 16 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/night/snow/sct?size=medium",
"shortForecast": "Slight Chance Snow Showers then Partly Cloudy",
"detailedForecast": "A slight chance of snow showers before 8pm. Partly cloudy, with a low around 30."
},
{
"number": 13,
"name": "Saturday",
"startTime": "2025-03-22T06:00:00-04:00",
"endTime": "2025-03-22T18:00:00-04:00",
"isDaytime": true,
"temperature": 52,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "9 to 13 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/day/sct?size=medium",
"shortForecast": "Mostly Sunny",
"detailedForecast": "Mostly sunny, with a high near 52."
},
{
"number": 14,
"name": "Saturday Night",
"startTime": "2025-03-22T18:00:00-04:00",
"endTime": "2025-03-23T06:00:00-04:00",
"isDaytime": false,
"temperature": 34,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": null
},
"windSpeed": "3 to 9 mph",
"windDirection": "NW",
"icon": "https://api.weather.gov/icons/land/night/bkn?size=medium",
"shortForecast": "Mostly Cloudy",
"detailedForecast": "Mostly cloudy, with a low around 34."
}
]
}
}
```
{{< unsafe >}}</details><br/>{{</unsafe >}}
The National Weather Service packs in so much weather information in just one API call! My favorite part is that they have a `detailedForecast` field which provides a nice human-readable description of the weather.
I don't know about you, but at any given time, I'm mostly curious about today and tomorrow's weather. Unless I'm planning a trip or need to be aware of an extreme weather event, the day's forecast mostly influences the clothes I wear.
The final part of this script is to grab the next three "periods" and display its `detailedForecast` field.
```bash
for i in 0 1 2; do
echo "$WEATHER" | jq .properties.periods[$i] | jq -r '
"\(.name)
\(.detailedForecast)
"
'
done
```
Instead of having to read an entire JSON message to get the weather, we now have a description of the forecast coming up.
```
This Afternoon
Cloudy, with a high near 69. South wind around 22 mph, with gusts as high as 43 mph. New rainfall amounts less than a tenth of an inch possible.
Tonight
A chance of rain showers before 8pm, then showers and thunderstorms. Cloudy, with a low around 50. Southwest wind 5 to 21 mph, with gusts as high as 44 mph. Chance of precipitation is 100%. New rainfall amounts between three quarters and one inch possible.
Monday
Rain showers likely. Cloudy. High near 53, with temperatures falling to around 46 in the afternoon. Northwest wind 5 to 12 mph. Chance of precipitation is 60%. New rainfall amounts between a half and three quarters of an inch possible.
```
Look how short and sweet that output is! With that, we have all the steps needed in our script to grab the upcoming forecast using the NWS API. I created an alias called `myweather` so that I don't have to memorize the latitude or longitude of where I live.
```bash
alias myweather='usweather 42.7289, -73.6915'
```
Here is the script that I call `usweather` in its entirety. I placed it in `~/.local/bin`.
```bash
#!/bin/sh
# Script to query the US National Weather Forecast Office (WFO)
set -o errexit
set -o nounset
show_usage() {
echo "Usage: usweather [lat] [lon]"
exit 1
}
# Check Argument Count
if [ "$#" -ne 2 ]; then
show_usage
fi
if ! command -v jq &> /dev/null; then
echo "jq is not installed"
exit 1
fi
# We need to figure out WFO specific parameters
POINTS=$(curl -Ls "https://api.weather.gov/points/$1,$2")
OFFICE=$(echo $POINTS | jq -r .properties.gridId)
X=$(echo $POINTS | jq .properties.gridX)
Y=$(echo $POINTS | jq .properties.gridY)
if [ "$OFFICE" = "null" ] || [ "$X" = "null" ] || [ "$Y" = "null" ]; then
echo -e "Error:\n $POINTS"
exit 1
fi
WEATHER=$(curl -Ls "https://api.weather.gov/gridpoints/$OFFICE/$X,$Y/forecast")
# Provide the detailed forecast for the next three weather periods
for i in 0 1 2; do
echo "$WEATHER" | jq .properties.periods[$i] | jq -r '
"\(.name)
\(.detailedForecast)
"
'
done
```

View file

@ -11,7 +11,7 @@ I've been coming across more [neocities](https://neocities.org/) websites recent
![Example Badge](/badges/fedora.gif) ![Example Badge](/badges/fedora.gif)
These web badges are often small images that shows a product or message. Historically, it dates back to when Netscape in 1996 made the [Netscape Now!](https://web.archive.org/web/20240914044400/https://sillydog.org/netscape/now.html) badge. These web badges are often small images that shows a product or message. Historically, it dates back to when Netscape in 1996 made the [Netscape Now!](https://sillydog.org/netscape/now.html) badge.
Since then, the Geocities picked it up and standardized many of the web badges to have a pixel size of 88x31. These badges are sometimes animated as GIFs, though they usually don't hold dynamic information. Since then, the Geocities picked it up and standardized many of the web badges to have a pixel size of 88x31. These badges are sometimes animated as GIFs, though they usually don't hold dynamic information.

View file

@ -2,7 +2,7 @@
title: "Writing Unit Tests in Lean 4" title: "Writing Unit Tests in Lean 4"
date: 2024-08-05T20:43:52-07:00 date: 2024-08-05T20:43:52-07:00
draft: false draft: false
tags: ["Formal Methods"] tags: []
math: false math: false
medium_enabled: false medium_enabled: false
--- ---

View file

@ -15,23 +15,34 @@ given: [https://rairlab.github.io/logic-group/](https://rairlab.github.io/logic-
I presented the following: I presented the following:
| Date | Title | 01/31/2024: An original talk titled "Planning under Qualitative Uncertainty - Initial Thoughts"
| ---------- | ------------------------------------------------------------ |
| 12/04/2024 | An Introduction to Situation Calculus (along with James Oswald) | 01/24/2024: An original talk titled "Spectra: STRIPS-Inspired AI Planner based on Automated Reasoning"
| 10/16/2024 | Alternative Theories of Uncertainty: Dempster-Shafer and Possibility Theory |
| 03/27/2024 | CryptoSolve: A Tool for the Analysis of Cryptographic Modes of Operation | 10/25/2023: An original talk titled "Introduction to Goal Recognition as Planning"
| 01/31/2024 | Planning under Qualitative Uncertainty - Initial Thoughts |
| 01/24/2024 | Spectra: STRIPS-Inspired AI Planner based on Automated Reasoning | 10/18/2023: Workshop along with James Oswald titled "RAIR Lab Software Overview"
| 10/25/2023 | Introduction to Goal Recognition as Planning |
| 10/18/2023 | RAIR Lab Software Overview Workshop (along with James Oswald) | 10/4/2023: An original talk on "Syntactic AC Unification"
| 10/4/2023 | Syntactic AC Unification |
| 09/06/2023 | Hierarchical Reinforcement Learning under Partial Observability with a Discovery Planning Model | 03/22/2023: Original Tutorial on ["Automated Theorem Proving with TPTP"](https://github.com/Brandon-Rozek/TPTP-Examples)
| 03/22/2023 | ["Automated Theorem Proving with TPTP Workshop"](https://github.com/Brandon-Rozek/TPTP-Examples) |
| 02/08/2023 | ["Interactive Theorem Proving with Lean Part 2"](/blog/lean3-tutorial/) | 02/08/2023: Original Tutorial on ["Interactive Theorem Proving with Lean Part 2"](/blog/lean3-tutorial/)
| 02/01/2023 | ["Interactive Theorem Proving with Lean Part 1"](/blog/lean3-tutorial/) |
| 10/19/2022 | [Evaluation of the Moral Permissibility of Action Plans](https://gki.informatik.uni-freiburg.de/papers/lindner-etal-aij2020.pdf) by Felix Lindner, Robert Mattmuller, and Bernhard Nebel | 02/01/2023: Original Tutorial on ["Interactive Theorem Proving with Lean Part 1"](/blog/lean3-tutorial/)
| 09/14/2022 | [Planning Modulo Theories: Extending the Planning Paradigm](https://ojs.aaai.org/index.php/ICAPS/article/download/13505/13354) by Peter Gregory, Derek Long, Maria Fox, and J. Christopher Beck. |
| 08/03/2022 | [Coming Up with Good Excuses: What To Do When No Plan Can be Found](https://www.aaai.org/ocs/index.php/ICAPS/ICAPS10/paper/viewFile/1453/1532) by Moritz Gobelbecker, Thomas Keller, Patrick Eyerich, Michael Brenner, and Bernhard Nebel. | 05/11/2022:
| 06/28/2022 | [Landmark-based heuristic online contingent planning](https://link.springer.com/article/10.1007/s10458-018-9389-9) by Shlomi Maliah, Guy Shani, and Ronen L. Brafman. | [The Power of Waiting in Social Laws](https://icaps21.icaps-conference.org/workshops/KEPS/Papers/KEPS_2021_paper_14.pdf) by Alexander Tuisov, Alexander Shleyfman, and Erez Karpas.
| 06/01/2022 | [AI Planning Annotation for Sample Efficient Reinforcement Learning](https://arxiv.org/pdf/2203.00669) by Junkyu Lee, Michael katz, Don Joven Agravante, Miao Liu, Geraud Nangue Tasse, Tim Linger, Shirin Sohrabi. |
| 05/11/2022 | [The Power of Waiting in Social Laws](https://icaps21.icaps-conference.org/workshops/KEPS/Papers/KEPS_2021_paper_14.pdf) by Alexander Tuisov, Alexander Shleyfman, and Erez Karpas. | 06/01/2022:
[AI Planning Annotation for Sample Efficient Reinforcement Learning](https://arxiv.org/pdf/2203.00669) by Junkyu Lee, Michael katz, Don Joven Agravante, Miao Liu, Geraud Nangue Tasse, Tim Linger, Shirin Sohrabi.
06/28/2022: [Landmark-based heuristic online contingent planning](https://link.springer.com/article/10.1007/s10458-018-9389-9) by Shlomi Maliah, Guy Shani, and Ronen L. Brafman.
08/03/2022: [Coming Up with Good Excuses: What To Do When No Plan Can be Found](https://www.aaai.org/ocs/index.php/ICAPS/ICAPS10/paper/viewFile/1453/1532) by Moritz Gobelbecker, Thomas Keller, Patrick Eyerich, Michael Brenner, and Bernhard Nebel.
09/14/2022: [Planning Modulo Theories: Extending the Planning Paradigm](https://ai.dmi.unibas.ch/papers/goebelbecker-et-al-icaps2010.pdf) by Peter Gregory, Derek Long, Maria Fox, and J. Christopher Beck.
10/19/2022: [Evaluation of the Moral Permissibility of Action Plans](https://gki.informatik.uni-freiburg.de/papers/lindner-etal-aij2020.pdf)
by Felix Lindner, Robert Mattmuller, and Bernhard Nebel.

View file

@ -3,44 +3,30 @@ title: Contact
description: Ways to contact Brandon Rozek description: Ways to contact Brandon Rozek
--- ---
Hi there! I'm happy that you're thinking about reaching out! If you're at a loss of words to say, feel free to engage me on my [research](/research) or my [interests](/interests). ## Email (Preferred)
**The best way to get a hold of me is through email.** I advocate the use of [plaintext](https://useplaintext.email/). My email address is [brozek@brandonrozek.com](mailto:brozek@brandonrozek.com). The best way to get a hold of me is through email. I advocate the use of [plaintext](https://useplaintext.email/). My email address is [brozek@brandonrozek.com](mailto:brozek@brandonrozek.com).
I support PGP encryption! My current fingerprint is: I support PGP encryption! My current fingerprint is:
``` ```
1623 A4C6 0EF7 B422 D2C8 9D5D 0610 BBE9 9025 8018 5F37 830B FA46 FF78 81F4 7AC7 8DF7 9C3D C5FC 658A
``` ```
You can query my keys through [WKD](https://wiki.gnupg.org/WKD) ([Direct Link](/.well-known/openpgpkey/hu/o1dbwkdx683fduwgzmrbwa3yip41frdn)) and the [OpenPGP Keyserver](https://keys.openpgp.org/search?q=brozek%40brandonrozek.com) ([Direct Link](https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=brozek@brandonrozek.com)). You can query my keys through [WKD](https://wiki.gnupg.org/WKD) ([Direct Link](/.well-known/openpgpkey/hu/o1dbwkdx683fduwgzmrbwa3yip41frdn)) and the [OpenPGP Keyserver](https://keys.openpgp.org/search?q=brozek%40brandonrozek.com) ([Direct Link](https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=brozek@brandonrozek.com)).
```bash
gpg --auto-key-locate wkd --locate-keys brozek@brandonrozek.com
```
For convinience, here's a form that you can use to send an encrypted email. This happens completely locally on your machine with [OpenPGP.js](https://openpgpjs.org/)! Keyoxide profiles:
[WKD Profile](https://keyoxide.org/wkd/brozek%40brandonrozek.com)
[HKP Profile](https://keyoxide.org/hkp/brozek%40brandonrozek.com)
For convinience, here's a form that you can use to send an encrypted email.
*Warning*: Some browsers have character limits in `mailto` links which can affect *Warning*: Some browsers have character limits in `mailto` links which can affect
the "Generate Email" button. the "Generate Email" button.
{{< pgpform "https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=brozek@brandonrozek.com" >}} {{< pgpform "https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=brozek@brandonrozek.com" >}}
This above encryption is performed locally on your machine with [OpenPGP.js](https://openpgpjs.org/).
Received a PGP-signed message from me? You can use the form below to verify locally that it was signed using my key. This method trusts that a malicious actor hasn't overriden my key on [keys.opengpg.org](https://keys.openpgp.org/). ## ActivityPub
{{< pgpverify "https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=brozek@brandonrozek.com" >}}
## Alternate Methods
You're also welcome to message me on Mastodon. My handle is [@brozek@fosstodon.org](https://fosstodon.org/@brozek). You're also welcome to message me on Mastodon. My handle is [@brozek@fosstodon.org](https://fosstodon.org/@brozek).
Check out my Keyoxide profiles:
[WKD Profile](https://keyoxide.org/wkd/brozek%40brandonrozek.com)
[HKP Profile](https://keyoxide.org/hkp/brozek%40brandonrozek.com)

View file

@ -9,8 +9,6 @@ description: Other places you can find Brandon at
- [Google Scholar](https://scholar.google.com/citations?user=JrgtnwgAAAAJ&hl=en) - [Google Scholar](https://scholar.google.com/citations?user=JrgtnwgAAAAJ&hl=en)
- [IndieWeb](https://indieweb.org/User:Brandonrozek.com) - [IndieWeb](https://indieweb.org/User:Brandonrozek.com)
- [Keybase](https://keybase.io/brozek) - [Keybase](https://keybase.io/brozek)
- [Keyoxide (HKP)](https://keyoxide.org/hkp/brozek%40brandonrozek.com)
- [Keyoxide (WKD)](https://keyoxide.org/wkd/brozek%40brandonrozek.com)
- [NPM](https://www.npmjs.com/~brandonrozek) - [NPM](https://www.npmjs.com/~brandonrozek)
- [OpenStreetMap](https://www.openstreetmap.org/user/Brandon%20Rozek) - [OpenStreetMap](https://www.openstreetmap.org/user/Brandon%20Rozek)
- [ORCiD](https://orcid.org/0000-0002-4537-559X) - [ORCiD](https://orcid.org/0000-0002-4537-559X)

View file

@ -1,147 +0,0 @@
---
title: Interests
description: Interests that Brandon Rozek has
---
Interested to know what I do in my free time or fun conversation topics to bring up? You've come to the right place! For my research interests, see [`/research`](/research).
## Reading blog posts
As you might be able to tell from my [Mastodon profile](https://fosstodon.org/@brozek), I'm not the most active on social media. Instead, I prefer to read blog posts. It serves a similar purposes to me. I know that I can follow Mastodon feeds using an RSS reader, but I really prefer to follow blogs where:
- The typical post is longer than a toot/tweet, my preference is a 5-8 minute read.
- There aren't consistently multiple posts per day. I don't want my RSS reader to be overwhelmed by a handful of people.
A great consequence of this is that there's a finite number of posts for me to check out per day.
Unfortunately, there seems to be a natural tendency over time for people to stop creating new posts. This means I am always on the hunt for new interesting blogs to follow. As of 2025, I follow 1355 RSS feeds. It's entirely likely that several hundred of these are dead. If you have a blog, reach out and let me know!
Every so often, I get asked for recommendations on which blogs to follow. Since the majority of the blogs I follow post less than once a week, often times those authors aren't top of mind. To get around this, I've created the [postroll](/postroll). This is a partial list of blog posts that I've enjoyed recently. My hope is that if you find their posts interesting too, that you would give them a follow!
## Going on walks
Spending the majority of my days sitting in front of a computer screen; I'm always happy when I take the time to go on a walk and admire nature's natural beauty.
My favorite walking trail near Troy, NY is at [Peebles Island State Park](https://parks.ny.gov/parks/111/details.aspx). They have a two mile perimeter loop around the island where you can look out into the Mohawk River. Depending on the water levels, there are also spots where you can walk into the river.
Near that park is the [Erie Canal Lock E-2](https://en.wikipedia.org/wiki/Waterford_Flight). It's in operation during the summer, and it's fun to see small boats move up and down in elevation.
Also near Troy, NY is [Grafton Lakes State Park](https://parks.ny.gov/parks/53/details.aspx). During the summer, you can canoe along the large lakes, and sometimes during the winter you can ~~walk on the ice~~ admire the frozen lakes. The Long Pond trail is covered in trees which gives you the great forest feel that you see in the Eastern coast of the US.
Sometimes, I feel like recording my GPS track and pictures and uploading them onto my website. You can find them at [`/tracks`](/tracks)
## Tinkering with technology
Never is there a dull moment in technology, there's always so much to learn. I enjoy diving into a project and sharing what I learn on my blog. While I tinker regularly at work, in my personal life, a lot of my blog posts stem from playing around with my website and self-hosting.
For example, tinkering with my website resulted in:
- [Rolling out my own CDN with GeoDNS](/blog/implementing-cdn-geodns/)
- [Listing Offline Pages with Service Workers](/blog/listing-offline-pages-service-workers/)
- [Linting my blog posts with Vale](/blog/vale-linter-human-prose/)
- [Mapping the states I visited](/blog/mapping-states-visited/)
While playing with my homelab led to:
- [Monitoring my Hard Drives with SMART Attributes](/blog/monitoring-disks-smartattributes/)
- [Accessing Homelab Services Remotely with mTLS](/blog/accessing-homelab-services-mtls/)
- [Webhook notifications on systemd service failure](/blog/webhook-notifications-on-systemd-service-failure/)
- [Setting up unprivileged containers with LXC on Fedora 38](/blog/lxc-fedora-38/)
I like to keep my eyes peeled for new projects to self-host. I really need to write a blog post on what services I'm currently running. Though the following services are tried and tested for me and I use them regularly:
[Hedgedoc](https://hedgedoc.org/): Superb-real-time-Markdown-collaboration tool! I use it multiple times a week for hashing out ideas with other people.
[Syncthing](https://hedgedoc.org/): File synchronization tool that has never failed me. I have an always-on instance on my server in an attempt to limit conflicts. You can even set it up so that you [don't use any of the public pools](/blog/private-syncthing-network/).
[Nextcloud](https://nextcloud.com/): File sharing tool which makes it easy way for me to create a share link that's password protected and expires. I don't really use its other features.
[Home Assistant](https://www.home-assistant.io/): Smart home automation. We all have to turn lights on and off somehow in the 21st century. Combine this with MQTT and lightbulbs/switches flashed with Tasmota, and you have a fully open-source smart home that operates only within your local LAN and magically works.
## Reading Manga
Having to read lots of dense technical content for work, I enjoy reading manga at night since it's typically less dense and includes lots of pictures. Also I enjoy stories that end, and don't feel like it has to drag on for >500 chapters.
The following is a sampling of manga I've enjoyed. As it's been some time since I've read some of these, the plot is not top of mind, so I won't go into the plot of these and instead give a high-level overview.
[Frieren: Beyond Journey's End](https://anilist.co/manga/118586/Frieren-Beyond-Journeys-End/)
The quintessential fantasy story following an elf mage named Frieren as she travels with her companions Fern and Stark. Living for more than 1000 years, Frieren has seen companions and even civilizations come and go. Honestly, the world-building is fantastic and I highly recommand you give this a read.
[Psuedo Harem](https://anilist.co/manga/105577/Giji-Harem/)
Benefit of dating a girl in the drama club? She can act out many personalities and provide a whole harem in one package. This manga is a cute light-hearted romance with comedic undertones as Rin acts as cool-chan, tsundere-chan, spoiled-chan, and four other personalities. Eiji, on the other hand as a non-actor who works on props for the club, replies to Rin's personalities in an awkward but lovable way.
[The Coppersmith's Bride](https://anilist.co/manga/117675/The-Coppersmiths-Bride/)
A cute manga about a girl named Shiina dating a coppersmith named Shuu. Lots of great character moments and overall a warm and fuzzy read.
[Don't Hurt Me, My Healer!](https://anilist.co/anime/132351/Kono-Healer-Mendokusai/)
Alvin the knight and Karla the healer join together to adventure in a comedic fantasy universe. The story focuses on their interactions with Karla regularly making jabs at Alvin. This story has an anime adaption, but honestly, the pace when reading the manga made me laugh out loud a lot more.
[Shrink: Psychiatrist Yowai](https://anilist.co/manga/114671/Shrink-Seishinkai-Yowai/)
Medical drama where Psychiatrist Konosuke Yowai helps his patients going through depression, bipolar disorder, eating disorders, PTSD, and others. The manga highlights the struggles that these patients face and points out how their country does not help given that their society doesn't fully recognize mental illnesses.
[Journey Home After School](https://anilist.co/manga/173062/Houkago-Kitaku-Biyori/)
Shun and Naoki are in the Going-Home club, and while that may seem boring, there's always a detour along the way! It's a slow paced wholesome romance between two high school kids and crazy enough no weird drama.
[Takako-san](https://anilist.co/manga/105353/Takakosan/)
A slice of life primarily focused on one person, Takako-san. She has better hearing than most and the chapters revolve around her processing the world around her.
[It Takes Two Tomorrow, Too](https://anilist.co/manga/110140/It-Takes-Two-Tomorrow-Too/)
Want to see a romantic slice-of-life story about a young couple living together? Then this is a story for you. It's a very wholesome story which teaches you to never steal your partner's pudding.
[News x It](https://anilist.co/manga/94552/News-x-It/)
A slapstick comedy where Saburou and Reiko are anchors trying their best to bring you the latest new stories. Except one of them might be a bit too lax on the delivery...
## Playing Video Games
Early in my childhood I played a lot of flash-based games on the Internet including:
- Blooms Tower Defense
- Learn to fly
- You can't help but root for the cute penguins.
- Pandemic
- Fancy Pants adventure
- Epic Battle fantasy
- McDonald's
- Yes this a real flash-game parody where you're trying to grow the empire. It captures the entire process: from growing soy, slaughtering cows, selling burgers, and do whatever the folks in HQ do.
In 2012, I got a steam account:
- Civilization V & VI
- Gotta love the multiplayer sessions where your friend is taking forever to decide what his nation should focus on for the next 100 years.
- Star Trek Online
- For some reason, the second hand market in this MMO was really good.
- Neverwinter
- Faster than Light
- Long Live the Queen
- Recettear: An Item Shop's Tale
- Strangely, I have a fond spot for shop management games.
A friend really enjoyed playing shooter games, so we played some together:
- Risk of Rain 1 & 2
- From a nostalgic standpoint, I like the first version a lot more. I have many memories trying to collect as many Barbed Wire as I can to fill up the entire screen. This might've caused a few of our runs to crash...
- Warframe
- Star Wars: Battlefront 2
In the last five years, two games that I've enjoyed are:
- Chrono Ark
- For the King I & II
Nowadays, I'm enjoying what Honkai Star Rail has to offer. Hoyoverse has really expanded over the years, take a look at the beautiful character trailers they're releasing on YouTube.
## Watching Hockey
During the winter season, when it gets dark at 4:30 PM. Nothing brings the hype back into the evenings like Hockey does.
It's a great experience! Clare and I bought season hockey passes for seeing RPI's hockey games. I write about it in more detail [here](/blog/ice-hockey/).
## Inactive Interests
The time I spend on my interests waxes and wanes and that's okay! I wrote a series of blog posts on [Amateur Radio](/tags/amateur-radio/), and while I do not partake in the hobby regularly currently, I still find it exciting.
Maybe I'll be convinced to get and play around with the Flipper Zero?

Binary file not shown.

View file

@ -71,9 +71,9 @@ An ideal $J$ of a commutative ring is said to be a **prime ideal** if for any tw
$$ $$
ab \in J \implies a \in J \text{ or } b \in J ab \in J \implies a \in J \text{ or } b \in J
$$ $$
**Theorem:** If $J$ is a prime ideal of a community ring with unity $A$, then the quotient ring $A / J$ is an integral domain. <u>Theorem:</u> If $J$ is a prime ideal of a community ring with unity $A$, then the quotient ring $A / J$ is an integral domain.
An ideal $J$ of $A$ with $J \ne A$ is called a **maximal ideal** if there exists no proper ideal $K$ of $A$ such that $J \subseteq K$ with $J \ne K$. An ideal $J$ of $A$ with $J \ne A$ is called a **maximal ideal** if there exists no proper ideal $K$ of $A$ such that $J \subseteq K$ with $J \ne K$.
**Theorem:** If $A$ is a commutative ring with unity, then $J$ is a maximal ideal of $A$ iff $A/J$ is a field. <u>Theorem:</u> If $A$ is a commutative ring with unity, then $J$ is a maximal ideal of $A$ iff $A/J$ is a field.

View file

@ -49,7 +49,7 @@ IterFibo(n):
Here the linear complexity becomes super apparent! Here the linear complexity becomes super apparent!
*Interesting snippet* <u>Interesting snippet</u>
"We had a very interesting gentleman in Washington named Wilson. He was secretary of Defense, and he actually had a pathological fear and hatred of the word *research*. Im not using the term lightly; Im using it precisely. His face would suffuse, he would turn red, and he would get violent if people used the term *research* in his presence. You can imagine how he felt, then, about the term *mathematical*.... I felt I had to do something to shield Wilson and the Air Force from the fact that I was really doing mathematics inside the RAND Corporation. What title, what name, could I choose?" "We had a very interesting gentleman in Washington named Wilson. He was secretary of Defense, and he actually had a pathological fear and hatred of the word *research*. Im not using the term lightly; Im using it precisely. His face would suffuse, he would turn red, and he would get violent if people used the term *research* in his presence. You can imagine how he felt, then, about the term *mathematical*.... I felt I had to do something to shield Wilson and the Air Force from the fact that I was really doing mathematics inside the RAND Corporation. What title, what name, could I choose?"

View file

@ -6,7 +6,7 @@ Falling under wrapper methods, optimality criterion are often used to aid in mod
## Akaike Information Criterion (AIC) ## Akaike Information Criterion (AIC)
AIC is an estimator of *relative<* quality of statistical models for a given set of data. Given a collection of models for the data, AIC estimates the quality of each model relative to each other. AIC is an estimator of <u>relative</u> quality of statistical models for a given set of data. Given a collection of models for the data, AIC estimates the quality of each model relative to each other.
This way, AIC provides a means for model selection. AIC offers an estimate of the relative information lost when a given model is used. This way, AIC provides a means for model selection. AIC offers an estimate of the relative information lost when a given model is used.
@ -79,7 +79,7 @@ $$
## Deviance Information Criterion ## Deviance Information Criterion
The DIC is a hierarchical modeling generalization of the AIC and BIC. it is useful in Bayesian model selection problems where posterior distributions of the model was *obtained by a Markov Chain Monte Carlo simulation*. The DIC is a hierarchical modeling generalization of the AIC and BIC. it is useful in Bayesian model selection problems where posterior distributions of the model was <u>obtained by a Markov Chain Monte Carlo simulation</u>.
This method is only valid if the posterior distribution is approximately multivariate normal. This method is only valid if the posterior distribution is approximately multivariate normal.

View file

@ -6,7 +6,7 @@ math: true
## Number of Solutions ## Number of Solutions
*For congruences mod 2* <u>For congruences mod 2</u>
**Proposition 16.1**. Let $f(x) = ax^2 + bx + c$ with $a$ odd, and let $\Delta = b^2 - 4ac$ be the discriminant of $f(x)$. Then, **Proposition 16.1**. Let $f(x) = ax^2 + bx + c$ with $a$ odd, and let $\Delta = b^2 - 4ac$ be the discriminant of $f(x)$. Then,

View file

@ -64,7 +64,7 @@ Let $s_1 > 0$ be arbitrary, and define $s_{n + 1} = \frac{1}{2}(s_n + \frac{a}{s
**Corollary:** If $X = (x_n) \subseteq \mathbb{R}$ has a subsequence that diverges then $X$ diverges. **Corollary:** If $X = (x_n) \subseteq \mathbb{R}$ has a subsequence that diverges then $X$ diverges.
**Monotone Sequence Theorem**: If $X = (x_n) \subseteq \mathbb{R}$, then it contains a *monotone subsequence*. **Monotone Sequence Theorem**: If $X = (x_n) \subseteq \mathbb{R}$, then it contains a <u>monotone subsequence</u>.
**Bolzano-Weierstrass Theorem:** Every bounded sequence in $\mathbb{R}$ has a convergent subsequence. **Bolzano-Weierstrass Theorem:** Every bounded sequence in $\mathbb{R}$ has a convergent subsequence.

View file

@ -1,12 +1,29 @@
--- ---
title: "Recently (May 2022)" title: Now
date: 2022-05-15T21:19:35-04:00 Description: Recent Happenings in Brandon Rozek's life
draft: false
tags: []
math: false
medium_enabled: false
--- ---
[*This is a now page, it's meant to showcase what's been going on in my life
recently. If you have a website, consider creating one as well*](https://nownownow.com/about)
Date: June 15, 2024
It's been two years since I've updated this page! Time goes by fast.
**Professional:** I'm well into the PhD program at this point. I've been fortunate enough to receive the NDSEG fellowship which funds my work, as well as many wonderful collaborators.
This summer, I'm an applied scientist intern at Amazon Web Services. I work on the [Cedar project](https://www.cedarpolicy.com/) which is under Automated Reasoning in Identities. I'm especially excited at the oppurtunity to write Lean code.
**Personal Life:** For the internship, I moved out to San Jose, California. The biggest surprise to me is just how blue the sky is almost every day!
There's a lot to explore here. I'm making edits on [OpenStreetMap](https://www.openstreetmap.org/user/Brandon%20Rozek/) using the Street Complete application on Android along the way.
---
---
Date: May 15, 2022
**Professional:** I started my PhD program back in August 2021. **Professional:** I started my PhD program back in August 2021.
So far, I've met many wonderful people including So far, I've met many wonderful people including

1
content/observations Submodule

@ -0,0 +1 @@
Subproject commit 6e40072a94110544cad527d28566068ff139d435

View file

@ -1,27 +0,0 @@
{{/* Get remote data. */}}
{{ $items := dict }}
{{ $url := "https://api.brandonrozek.com/observations" }}
{{ with try (resources.GetRemote $url ) }}
{{ with .Err }}
{{ errorf "Unable to get remote resource %s: %s" $url . }}
{{ else with .Value }}
{{ $items = . | transform.Unmarshal }}
{{ else }}
{{ errorf "Unable to get remote resource %s" $url }}
{{ end }}
{{ end }}
{{ range $items.observations }}
{{ $dates := dict "date" (time.AsTime .created_at) }}
{{ $params := . }}
{{ $page := dict
"content" (dict "mediaType" "text/markdown" "value" "")
"dates" $dates
"kind" "page"
"params" $params
"path" .id
"title" ""
"build" (dict "render" "never")
}}
{{ $.AddPage $page }}
{{ end }}

View file

@ -49,7 +49,7 @@ async function listPages() {
if (post.headers.get('content-type').includes('text/html')) { if (post.headers.get('content-type').includes('text/html')) {
const body = await post.text(); const body = await post.text();
console.log(body) console.log(body)
const title = body.match(/<title>(.*)<\/title>/)[1].replace("| Brandon Rozek", ""); const title = body.match(/<title>(.*)<\/title>/)[1];
result.push({ result.push({
url, url,
post, post,

View file

@ -7,7 +7,7 @@ authors: [
"Veena Ravishankar", "Veena Ravishankar",
"Brandon Rozek" "Brandon Rozek"
] ]
date: 2020-06-01 date: 2020-06
publish_date: "2020/6" publish_date: "2020/6"
conference: "International Workshop on Unification" conference: "International Workshop on Unification"
firstpage: 58 firstpage: 58

View file

@ -7,7 +7,7 @@ authors: [
"Selmer Bringsjord", "Selmer Bringsjord",
"Naveen Sundar Govindarajulu" "Naveen Sundar Govindarajulu"
] ]
date: 2022-07-01 date: 2022-07
publish_date: "2022/07" publish_date: "2022/07"
conference: "International Conference on Robot Ethics and Standards" conference: "International Conference on Robot Ethics and Standards"
isbn: "978-1-7396142-0-1" isbn: "978-1-7396142-0-1"

View file

@ -1,21 +0,0 @@
---
draft: false
title: "Guiding Hiearchical Reinforcement Learning in Partially Observable Environments with AI Planning"
authors: [
"Brandon Rozek",
"Junkyu Lee",
"Harsha Kokel",
"Michael Katz",
"Shirin Sohrabi"
]
date: 2024-06-02
publish_date: "2024/06/02"
conference: "International Workshop on Bridging the Gap Between AI Planning and Reinforcement Learning (PRL)"
isbn: ""
doi: ""
language: "English"
pdf_url: "https://prl-theworkshop.github.io/prl2024-icaps/papers/12.pdf"
abstract: "Partially observable Markov decision processes challenge reinforcement learning agents since observations provide an limited view of the environment. This often requires an agent to explore collecting observations to form the necessary state information to complete the task. Even assuming knowledge is monotonic, it is difficult to know when to stop exploration. We integrate AI planning within hierarchical reinforcement learning to aide in the exploration of partially observable environments. Given a set of unknown state variables, their potential valuations, along with which abstract operators may discover them, we create an abstract fully-observable non-deterministic planning problem which captures the agents abstract belief state. This decomposes the POMDP into a tree of semi-POMDPs based on sensing outcomes. We evaluate our agents performance on a MiniGrid domain and show how guided exploration may improve agent performance."
---

View file

@ -1,18 +0,0 @@
---
draft: false
title: "Initial Steps in Planning under Qualitative Uncertainty"
authors: [
"Brandon Rozek",
"Selmer Bringsjord"
]
date: 2024-06-02
publish_date: "2024/06/02"
conference: "International Workshop on Human-Aware and Explainable Planning (HAXP)"
isbn: ""
doi: ""
language: "English"
pdf_url: "https://openreview.net/pdf?id=soH9BIp0pL"
abstract: "Techniques in automated planning under uncertainty capture whether an agent believes that a ground atomic formula is true, false, or uncertain; and, in some cases, the exact probability that its true at a given state. Sometimes, however, an agent does not have access to exact probabilistic information, but is instead able to judge the uncertainty qualitatively. We take initial but substantial steps towards characterizing a variant of conformant planning based on qualitative uncertainty. Our framework, QU-STRIPS, introduces levels of belief about ground atomic formulae which stratify uncertainty ranging on the negative side from certainly not, to agnostic, and then on the positive side up to certainly. In order to efficiently find plans, we present a sound compilation into classical STRIPS. We provide preliminary results on a new escape domain and show that state-of-the-art planners can effectively find plans that achieve the goal at a high positive belief level, while considering the trade-off between the strength of a plan and its cost."
---

View file

@ -1,28 +0,0 @@
{{/* Get remote data. */}}
{{ $items := dict }}
{{ $url := "https://api.brandonrozek.com/postroll" }}
{{ with try (resources.GetRemote $url ) }}
{{ with .Err }}
{{ errorf "Unable to get remote resource %s: %s" $url . }}
{{ else with .Value }}
{{ $items = . | transform.Unmarshal }}
{{ else }}
{{ errorf "Unable to get remote resource %s" $url }}
{{ end }}
{{ end }}
{{ range $items.Ok }}
{{ $content := dict "mediaType" "text/markdown" "value" .comment }}
{{ $dates := dict "date" (time.AsTime .dateadded) }}
{{ $params := dict "url" .url "author" .author }}
{{ $page := dict
"content" $content
"dates" $dates
"kind" "page"
"params" $params
"path" .title
"title" .title
"build" (dict "render" "never")
}}
{{ $.AddPage $page }}
{{ end }}

View file

@ -1,8 +0,0 @@
---
title: Postroll
description: Recently enjoyed blog posts
---
Inspired by [Jedda's Postroll](https://notes.jeddacp.com/postroll/), here is an incomplete list of blog posts that I've read and enjoyed in the last 3 months. This list refreshes daily.
If you find any of these posts interesting, I suggest that you give them a follow!

View file

@ -7,15 +7,16 @@ layout: revision
guid: http://brandonrozek.com/2016/10/362-revision-v1/ guid: http://brandonrozek.com/2016/10/362-revision-v1/
permalink: /2016/10/362-revision-v1/ permalink: /2016/10/362-revision-v1/
--- ---
<img src="https://brandonrozek.com/wp-content/uploads/2016/10/Math-I-O.png" alt="Screenshot of the Math I/O Website" width="1208" height="604" class="alignnone size-full wp-image-30" />
![Screenshot of the Math I/O Website](/files/images/projects/Math-I-O.png) ### [Math I/O](http://math-io.com) {.project-title}
### [Math I/O](http://math-io.com)
Math I/O is a website I founded with [David Thames](http://davidcthames.com) and Stephen Shamaiengar. The goal of this website is to help reinforce high school level math concepts in the form of enjoyable games. Most of the games are made using HTML5 Canvas and Javascript. You can check them out [here](http://math-io.com/). Math I/O is a website I founded with [David Thames](http://davidcthames.com) and Stephen Shamaiengar. The goal of this website is to help reinforce high school level math concepts in the form of enjoyable games. Most of the games are made using HTML5 Canvas and Javascript. You can check them out [here](http://math-io.com/).
<!--more-->
I ran Math I/O for a year until I moved away from the area. During that year, I worked on the Darts game, Speed Transformations, and Theta. I then took about a year off to get adjusted to my new place when I moved. I ran Math I/O for a year until I moved away from the area. During that year, I worked on the Darts game, Speed Transformations, and Theta. I then took about a year off to get adjusted to my new place when I moved.
While I was away, Math I/O gained many new people, making it hard for them to work as one large group. David then decided to split the group up into smaller teams, inviting me to come back and lead one. I never ran a team remotely before, so I was excited to see how it would be like. While I was away, Math I/O gained many new people, making it hard for them to work as one large group. David then decided to split the group up into smaller teams, inviting me to come back and lead one. I never ran a team remotely before, so I was excited to see how it would be like.
The team I lead are mostly full of people starting out in programming. To help them out, I started giving lectures once a week to introduce concepts, and posted them here on my writings page. We would then practice these concepts while making a new game during the meetings. I couldn't ask for a better team, their enthusiasm drives me to keep working at Math I/O. The team I lead are mostly full of people starting out in programming. To help them out, I started giving lectures once a week to introduce concepts, and posted them here on my writings page. We would then practice these concepts while making a new game during the meetings. I couldn&#8217;t ask for a better team, their enthusiasm drives me to keep working at Math I/O.

View file

@ -7,10 +7,14 @@ layout: revision
guid: http://brandonrozek.com/2016/10/360-revision-v1/ guid: http://brandonrozek.com/2016/10/360-revision-v1/
permalink: /2016/10/360-revision-v1/ permalink: /2016/10/360-revision-v1/
--- ---
![](/files/images/projects/SentenceWorthy.jpg) <img class="alignnone size-full wp-image-176" src="https://brandonrozek.com/wp-content/uploads/2016/10/SentenceWorthy.jpg" alt="SentenceWorthy" width="1264" height="964" />
### [Sentence Worthy](http://sentenceworthy.com) ### [Sentence Worthy](http://sentenceworthy.com) {.project-title}
Sentence Worthy is a side project created by [Tori Dayton](http://toridayton.com) and I. We combine both of our passions, writing and photography, and make something for others to enjoy. Have a look at our [creation](http://sentenceworthy.com). Sentence Worthy is a side project created by [Tori Dayton](http://toridayton.com) and I. We combine both of our passions, writing and photography, and make something for others to enjoy. Have a look at our [creation](http://sentenceworthy.com).
<!--more-->
I am the main developer and photographer of this site. I head out every so often and take pictures of whatever interests me. Then, I email Tori my choice picks and she tells me what she wants to do with the pictures and what ideas she has for them. I then edit the picture with her ideas in mind. After we go back and forth on the picture edits, Tori sends me a one sentence story she made that goes along with the picture. The picture and story then get published together onto the website. Hence the tagline, every picture is worth a sentence. I am the main developer and photographer of this site. I head out every so often and take pictures of whatever interests me. Then, I email Tori my choice picks and she tells me what she wants to do with the pictures and what ideas she has for them. I then edit the picture with her ideas in mind. After we go back and forth on the picture edits, Tori sends me a one sentence story she made that goes along with the picture. The picture and story then get published together onto the website. Hence the tagline, every picture is worth a sentence.
<!--more-->

View file

@ -7,11 +7,12 @@ layout: revision
guid: http://brandonrozek.com/2016/10/364-revision-v1/ guid: http://brandonrozek.com/2016/10/364-revision-v1/
permalink: /2016/10/364-revision-v1/ permalink: /2016/10/364-revision-v1/
--- ---
<img class="alignnone size-full wp-image-14" src="https://brandonrozek.com/wp-content/uploads/2016/10/Tori-Dayton-1.png" alt="Screenshot of Tori Dayton's website" width="1430" height="944" />
![Screenshot of Tori Dayton's website](/files/images/projects/Tori-Dayton-1.png)
### [Tori Dayton](http://toridayton.com) {.project-title} ### [Tori Dayton](http://toridayton.com) {.project-title}
Tori Dayton is a great friend and poet, this is the site I made for her to showcase her writings. It's the first WordPress project I worked on and it set the tone for all the future ones I did. Check out her [writings!](http://toridayton.com/work) I'm a fan of her work. (Not biased at all) Tori Dayton is a great friend and poet, this is the site I made for her to showcase her writings. It&#8217;s the first WordPress project I worked on and it set the tone for all the future ones I did. Check out her [writings!](http://toridayton.com/work) I&#8217;m a fan of her work. (Not biased at all)
<!--more-->
Fun Fact: I also worked on the [Tori Bot](http://toridayton.com/category/tori-bot/) on the site. Tori Bot takes existing poems and tries to generate a new one using the [Natural Language Toolkit](http://www.nltk.org/) library made for Python. Fun Fact: I also worked on the [Tori Bot](http://toridayton.com/category/tori-bot/) on the site. Tori Bot takes existing poems and tries to generate a new one using the [Natural Language Toolkit](http://www.nltk.org/) library made for Python.

View file

@ -8,11 +8,6 @@ aliases:
## Publications ## Publications
A Modal Logic of Optimality (Student Abstract)
- Authors: James T. Oswald, *Brandon Rozek*, Thomas M. Ferguson, Selmer Bringsjord
- Venue: AAAI Conference on Artificial Intelligence, 2025.
- [Paper](https://ojs.aaai.org/index.php/AAAI/article/view/35286/37441)
[Modeling C0 Family Logics for Artificial Intelligence: Doxastic-Temporal Logics for Reasoning About Goals](/paper/2405.02) [Modeling C0 Family Logics for Artificial Intelligence: Doxastic-Temporal Logics for Reasoning About Goals](/paper/2405.02)
- Authors: James T. Oswald, *Brandon Rozek*, and Thomas M. Ferguson - Authors: James T. Oswald, *Brandon Rozek*, and Thomas M. Ferguson
- Venue: Künstliche Intelligenz (KI), 2024 - Venue: Künstliche Intelligenz (KI), 2024
@ -58,15 +53,15 @@ Verification of Automatically Synthesized Cryptosystems ](/paper/2109.01/)
## Papers ## Papers
[Initial Steps in Planning under Qualitative Uncertainty](/paper/2406.02) Initial Steps in Planning under Qualitative Uncertainty
- Authors: *Brandon Rozek* and Selmer Bringsjord - Authors: *Brandon Rozek* and Selmer Bringsjord
- Venue: International Workshop on Human-Aware and Explainable Planning (HAXP), 2024 - Venue: International Workshop on Human-Aware and Explainable Planning (HAXP), 2024
- [Paper](https://openreview.net/pdf?id=soH9BIp0pL) - Paper to appear mid 2024
[Guiding Hiearchical Reinforcement Learning in Partially Observable Environments with AI Planning](/paper/2406.01) Guiding Hiearchical Reinforcement Learning in Partially Observable Environments with AI Planning
- Authors: *Brandon Rozek*, Junkyu Lee, Harsha Kokel, Michael Katz, Shirin Sohrabi - Authors: *Brandon Rozek*, Junkyu Lee, Harsha Kokel, Michael Katz, Shirin Sohrabi
- Venue: International Workshop on Bridging the Gap Between AI Planning and Reinforcement Learning (PRL), 2024 - Venue: International Workshop on Bridging the Gap Between AI Planning and Reinforcement Learning (PRL), 2024
- [Paper](https://prl-theworkshop.github.io/prl2024-icaps/papers/12.pdf) - Paper to appear mid 2024
[CryptoSolve: Towards a Tool for the Symbolic Analysis of Cryptographic Algorithms](/paper/2203.01/) [CryptoSolve: Towards a Tool for the Symbolic Analysis of Cryptographic Algorithms](/paper/2203.01/)
- Authors: D Chichester, W Du, R Kauffman, H Lin, C Lynch, A M. Marshall, C Meadows, P Narendran, V Ravishankar, L Rovira, *B Rozek* - Authors: D Chichester, W Du, R Kauffman, H Lin, C Lynch, A M. Marshall, C Meadows, P Narendran, V Ravishankar, L Rovira, *B Rozek*

View file

@ -24,11 +24,11 @@ An extensive list of similarity measures for binary data exist, the reason for s
In some cases, zero-zero matches are equivalent to one-one matches and therefore should be included in the calculated similarity measure In some cases, zero-zero matches are equivalent to one-one matches and therefore should be included in the calculated similarity measure
**Example**: Gender, where there is no preference as to which of the two categories should be coded as zero or one <u>Example</u>: Gender, where there is no preference as to which of the two categories should be coded as zero or one
In other cases the inclusion or otherwise of the matches is more problematic In other cases the inclusion or otherwise of the matches is more problematic
**Example**: When the zero category corresponds to the genuine absence of some property, such as wings in a study of insects <u>Example</u>: When the zero category corresponds to the genuine absence of some property, such as wings in a study of insects
The question that then needs to be asked is do the co-absences contain useful information about the similarity of the two objects? The question that then needs to be asked is do the co-absences contain useful information about the similarity of the two objects?
@ -152,7 +152,7 @@ Since for correlation coefficients we have that $-1 \le \phi_{ij} \le 1$ with th
The use of correlation coefficients in this context is far more contentious than its noncontroversial role in assessing the linear relationship between two variables based on $n$ observations. The use of correlation coefficients in this context is far more contentious than its noncontroversial role in assessing the linear relationship between two variables based on $n$ observations.
When correlations between two individuals are used to quantify their similarity the *rows of the data matrix are standardized*, not its columns. When correlations between two individuals are used to quantify their similarity the <u>rows of the data matrix are standardized</u>, not its columns.
**Disadvantages** **Disadvantages**
@ -164,7 +164,7 @@ In addition, the correlation coefficient is unable to measure the difference in
However, the use of a correlation coefficient can be justified for situations where all of the variables have been measured on the same scale and precise values taken are important only to the extent that they provide information about the subject's relative profile However, the use of a correlation coefficient can be justified for situations where all of the variables have been measured on the same scale and precise values taken are important only to the extent that they provide information about the subject's relative profile
**Example:** In classifying animals or plants, the absolute size of the organisms or their parts are often less important than their shapes. In such studies the investigator requires a dissimilarity coefficient that takes the value zero if and only if two individuals' profiles are multiples of each other. The angular separation dissimilarity measure has this property. <u>Example:</u> In classifying animals or plants, the absolute size of the organisms or their parts are often less important than their shapes. In such studies the investigator requires a dissimilarity coefficient that takes the value zero if and only if two individuals' profiles are multiples of each other. The angular separation dissimilarity measure has this property.
**Further considerations** **Further considerations**
@ -271,26 +271,25 @@ By also employing within-group correlations, the Mahalanobis distance takes acco
The use of Mahalanobis implies that the investigator is willing to **assume** that the covariance matrices are at least approximately the same in the two groups. When this is not so, this measure is an inappropriate inter-group measure. Other alternatives exist such as the one proposed by Anderson and Bahadur The use of Mahalanobis implies that the investigator is willing to **assume** that the covariance matrices are at least approximately the same in the two groups. When this is not so, this measure is an inappropriate inter-group measure. Other alternatives exist such as the one proposed by Anderson and Bahadur
![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczM3L2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkxLWdtaWY-) <img src="http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczM3L2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkxLWdtaWY-" alt="equation">
Another alternative is the *normal information radius* suggested by Jardine and Sibson Another alternative is the *normal information radius* suggested by Jardine and Sibson
![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczM4L2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkxLWdtaWY-) <img src="http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczM4L2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkxLWdtaWY-" alt="equation">
### Inter-group Proximity Based on Group Summaries for Categorical Data ### Inter-group Proximity Based on Group Summaries for Categorical Data
Approaches for measuring inter-group dissimilarities between groups of individuals for which categorical variables have been observed have been considered by a number of authors. Balakrishnan and Sanghvi (1968), for example, proposed a dissimilarity index of the form Approaches for measuring inter-group dissimilarities between groups of individuals for which categorical variables have been observed have been considered by a number of authors. Balakrishnan and Sanghvi (1968), for example, proposed a dissimilarity index of the form
![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczMwL2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkyLWdtaWY-) ![equation](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczMwL2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkyLWdtaWY-)
where $p_{Akl}$ and $p_{Bkl}$ are the proportions of the lth category of the kth variable in group A and B respectively, ![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnMi8zbGVpL3RtYTBjbmdzaWUuMGlpbg--), ck + 1 is the number of categories for the kth variable and p is the number of variables. where $p_{Akl}$ and $p_{Bkl}$ are the proportions of the lth category of the kth variable in group A and B respectively, ![img](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnMi8zbGVpL3RtYTBjbmdzaWUuMGlpbg--), ck + 1 is the number of categories for the kth variable and p is the number of variables.
Kurczynski (1969) suggested adapting the generalized Mahalanobis distance, with categorical variables replacing quantitative variables. In its most general form, this measure for inter-group distance is given by Kurczynski (1969) suggested adapting the generalized Mahalanobis distance, with categorical variables replacing quantitative variables. In its most general form, this measure for inter-group distance is given by
![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczMxL2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkyLWdtaWY-) ![equation](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczMxL2UwLXMzL2VpL3RtYTBjMGdzY2QwLmkyLWdtaWY-)
where ![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnMy8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) contains sample proportions in group A and ![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNC8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) is defined in a similar manner, and ![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNS8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) is the m × m common sample covariance matrix, where ![](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNi8zbGVpL3RtYTBjbmdzaWUuMGlpbg--). where ![img](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnMy8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) contains sample proportions in group A and ![img](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNC8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) is defined in a similar manner, and ![img](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNS8zbGVpL3RtYTBjbmdzaWUuMGlpbg--) is the m × m common sample covariance matrix, where ![img](http://proquest.safaribooksonline.com.ezproxy.umw.edu/getfile?item=cjlhZWEzNDg0N2R0cGMvaS9zMG1nODk0czcvN3MwczNmL2VnNi8zbGVpL3RtYTBjbmdzaWUuMGlpbg--).
## Weighting Variables ## Weighting Variables

View file

@ -11,9 +11,9 @@ Hierarchal Clustering techniques can be subdivided depending on the method of go
First there are two different methods in forming the clusters *Agglomerative* and *Divisive* First there are two different methods in forming the clusters *Agglomerative* and *Divisive*
**Agglomerative** is when you combine the n individuals into groups through each iteration <u>Agglomerative</u> is when you combine the n individuals into groups through each iteration
**Divisive** is when you are separating one giant group into finer groupings with each iteration. <u>Divisive</u> is when you are separating one giant group into finer groupings with each iteration.
Hierarchical methods are an irrevocable algorithm, once it joins or separates a grouping, it cannot be undone. As Kaufman and Rousseeuw (1990) colorfully comment: *"A hierarchical method suffers from the defect that it can never repair what was done in previous steps"*. Hierarchical methods are an irrevocable algorithm, once it joins or separates a grouping, it cannot be undone. As Kaufman and Rousseeuw (1990) colorfully comment: *"A hierarchical method suffers from the defect that it can never repair what was done in previous steps"*.

View file

@ -130,7 +130,7 @@ These events coincide every twenty years, because $lcm(4, 10) = 20$.
We are not always interested in full answers, however. Sometimes the remainder suffices for our purposes. We are not always interested in full answers, however. Sometimes the remainder suffices for our purposes.
**Example:** Suppose your birthday this year falls on a Wednesday. What day of the week will it fall on next year? <u>Example:</u> Suppose your birthday this year falls on a Wednesday. What day of the week will it fall on next year?
The remainder of the number of days between now and then (365 or 366) mod the number of days in a week. $365$ mod $7 = 1$. Which means that your birthday will fall on a Thursday. The remainder of the number of days between now and then (365 or 366) mod the number of days in a week. $365$ mod $7 = 1$. Which means that your birthday will fall on a Thursday.
@ -138,7 +138,7 @@ The remainder of the number of days between now and then (365 or 366) mod the nu
**Addition**: $(x + y)$ mod $n$ $=$ $((x $ mod $n) + (y$ mod $n))$ mod $n$ **Addition**: $(x + y)$ mod $n$ $=$ $((x $ mod $n) + (y$ mod $n))$ mod $n$
**Example:** How much small change will I have if given \$123.45 by my mother and \$94.67 by my father? <u>Example:</u> How much small change will I have if given \$123.45 by my mother and \$94.67 by my father?
$$ $$
\begin{align*} \begin{align*}
(12345 \text{ mod } 100) + (9467 \text{ mod } 100) &= (45 + 67) \text{ mod } 100 \\ (12345 \text{ mod } 100) + (9467 \text{ mod } 100) &= (45 + 67) \text{ mod } 100 \\
@ -147,7 +147,7 @@ $$
$$ $$
**Subtraction** (Essentially addition with negatives): **Subtraction** (Essentially addition with negatives):
**Example:** Based on the previous example, how much small change will I have after spending \$52.53? <u>Example:</u> Based on the previous example, how much small change will I have after spending \$52.53?
$$ $$
(12 \text{ mod } 100) - (53 \text{ mod } 100) = -41 \text{ mod } 100 = 59 \text{ mod } 100 (12 \text{ mod } 100) - (53 \text{ mod } 100) = -41 \text{ mod } 100 = 59 \text{ mod } 100
$$ $$
@ -159,7 +159,7 @@ $$
$$ $$
xy \text{ mod } n = (x \text{ mod } n)(y \text{ mod } n) \text{ mod n} xy \text{ mod } n = (x \text{ mod } n)(y \text{ mod } n) \text{ mod n}
$$ $$
**Example:** How much change will you have if you earn \$17.28 per hour for 2,143 hours? <u>Example:</u> How much change will you have if you earn \$17.28 per hour for 2,143 hours?
$$ $$
\begin{align*} \begin{align*}
(1728 * 2143) \text{ mod } 100 &= (28 \text{ mod } 100)(43 \text{ mod 100}) \\ (1728 * 2143) \text{ mod } 100 &= (28 \text{ mod } 100)(43 \text{ mod 100}) \\
@ -170,7 +170,7 @@ $$
$$ $$
x^y \text{ mod } n =(x \text{ mod n})^y \text{ mod } n x^y \text{ mod } n =(x \text{ mod n})^y \text{ mod } n
$$ $$
**Example:** What is the last digit of $2^{100}$? <u>Example:</u> What is the last digit of $2^{100}$?
$$ $$
\begin{align*} \begin{align*}
2^3 \text{ mod } 10 &= 8 \\ 2^3 \text{ mod } 10 &= 8 \\

View file

@ -24,7 +24,7 @@ This algorithm is called *iterative policy evaluation*.
To produce each successive approximation, $v_{k + 1}$ from $v_k$, iterative policy evaluation applies the same operation to each state $s$: it replaces the old value of $s$ with a new value obtained from the old values of the successor states of $s$, and the expected immediate rewards, along all the one-step transitions possible under the policy being evaluated. To produce each successive approximation, $v_{k + 1}$ from $v_k$, iterative policy evaluation applies the same operation to each state $s$: it replaces the old value of $s$ with a new value obtained from the old values of the successor states of $s$, and the expected immediate rewards, along all the one-step transitions possible under the policy being evaluated.
**Iterative Policy Evaluation** <u>**Iterative Policy Evaluation**</u>
``` ```
Input π, the policy to be evaluated Input π, the policy to be evaluated
@ -69,7 +69,7 @@ Each policy is guaranteed to be a strict improvement over the previous one (unle
This way of finding an optimal policy is called *policy iteration*. This way of finding an optimal policy is called *policy iteration*.
**Algorithm** <u>Algorithm</u>
``` ```
1. Initialization 1. Initialization

Some files were not shown because too many files have changed in this diff Show more