diff --git a/about/index.html b/about/index.html index 353f5e1..afd33d0 100644 --- a/about/index.html +++ b/about/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm diff --git a/bundle.css b/bundle.css index e14ec50..14044e1 100644 --- a/bundle.css +++ b/bundle.css @@ -61,15 +61,17 @@ h2 { button { padding: 5px; - background-color: #2c3e50; + background-color: #e74c3c; color: white; border-radius: 8px; - transition-duration: 200ms; + transition-duration: 400ms; } button:hover { - padding: 8px; + padding-right: 15px; + padding-left: 15px; transition-duration: 200ms; + background-color: #a5392c; } .deemphasis { @@ -82,24 +84,22 @@ button:hover { margin-top: 25px; } .post-card { - background-color: #bdc3c7; + background-color: #2c3e50; padding: 25px; - border: 2px solid #7f8c8d; + border: 3px solid #34495e; + box-shadow: 15px 8px #e74c3c; border-radius: 8px; margin: 25px; + color: white; } -.tag-button { - background-color: #e74c3c; +.post-card a{ + text-decoration: none; color: white; - width: fit-content; - height: fit-content; - border-radius: 8px; - } -.tag-button p { - padding: 5px; +.post-card h3 { + border-bottom: 3px solid #e74c3c; } .skill-card-container { diff --git a/index.html b/index.html index 70f24ae..1bba29a 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm @@ -48,7 +48,18 @@

I write about coding, algorithms, and systems.

Blog Posts

-

Learning Rust the Hard Way: Part 1

+

Writing Custom Site Analytics: Part 1

+

Anonymous Statistics

+

I want to record traffic to my site, but I want to make sure that the statistics are anonymous. Let's practice our Javascript and system design.

+ + + +
+ + +
+

Learning Rust the Hard Way: Recreating the touch Linux Command

+

Recreating the touch Linux Command

I'm trying to break into the industry, and I think knowing the memory-safe programming language Rust will set me apart from my peers. Let's begin this journey.

diff --git a/js/portfolio.js b/js/portfolio.js new file mode 100644 index 0000000..83f5059 --- /dev/null +++ b/js/portfolio.js @@ -0,0 +1,40 @@ +// Add event listeners to the skill cards +const skillCards = document.getElementsByClassName("skill-card"); +for (let card of skillCards) { + console.log(card); + card.addEventListener("mouseover", function focusElement() { + let cardHeader = this.querySelector("h2"); + + this.style.transitionDuration = "200ms"; + this.style.backgroundColor = "#e74c3c"; + this.style.padding = "20px"; + + cardHeader.style.transitionDuration = "400ms"; + cardHeader.style.fontSize = "2rem"; + + + }); + + card.addEventListener("mouseout", function unfocusElement(e) { + this.style.backgroundColor = "#2c3e50"; + this.style.padding = "10px"; + + let cardHeader = this.querySelector("h2"); + cardHeader.style.transitionDuration = "200ms"; + cardHeader.style.fontSize = "1.5rem"; + }); + +} + +function showDetails(elem) { + let projectDetailsId = "project-details-" + elem.id; + let details = document.getElementById(projectDetailsId); + if (details.style.display === "none") { + console.log("DISPLAYING"); + details.style.display = "block"; + elem.textContent = "Show Less"; + } else { + details.style.display = "none"; + elem.textContent = "Show More"; + } +} diff --git a/portfolio/index.html b/portfolio/index.html index 2b22072..8b0c70d 100644 --- a/portfolio/index.html +++ b/portfolio/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm @@ -31,7 +31,7 @@

Projects Portfolio -
+

Hi! I'm Gage.

diff --git a/posts/index.html b/posts/index.html index 30e17a1..49a124d 100644 --- a/posts/index.html +++ b/posts/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm @@ -41,7 +41,7 @@

Rust

rust

-

Learning Rust the Hard Way: Part 1

+

Learning Rust the Hard Way: Recreating the touch Linux Command

I'm trying to break into the industry, and I think knowing the memory-safe programming language Rust will set me apart from my peers. Let's begin this journey.

diff --git a/posts/learning-rust-part-1/index.html b/posts/learning-rust-part-1/index.html index e0cf999..fc568fe 100644 --- a/posts/learning-rust-part-1/index.html +++ b/posts/learning-rust-part-1/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm diff --git a/posts/writing-custom-site-analytics/index.html b/posts/writing-custom-site-analytics/index.html new file mode 100644 index 0000000..41ff43c --- /dev/null +++ b/posts/writing-custom-site-analytics/index.html @@ -0,0 +1,202 @@ + + + + + + + + + + + + Failed Algorithm + + +
+

+ Failed Algorithm
+ A Personal Blog by Gage Schaffer +

+
+ +

Writing Custom Site Analytics: Part 1 - Getting Information from the Client

+

I want to record how many visitors I get on my site. I'll give you a hint: it's not many. However, I would like a general number.

+

This kind of project also helps me practice my system design a little bit, because there's a unique challenge: How can I call an API using Javascript while keeping that API secure? I don't want bad actors enumerating my API and potentially getting access to my data.

+

Let's dive in.

+

Information Gathering

+

One very important part of this project is that the information has to be anonymous. No IP addresses, no hardware information, no geolocation, etc. So what can we gather?

+

Well, for starters, we can gather that a page view did, in fact, take place. Let's start there.

+

Setting up the Event Listener

+

We'll need to set up an event listener and detect when the page loads. After the page loads, we'll wait just a few seconds to make sure the site visit was actually done by a human.

+
// littleBrother.js
+
+document.addEventListener('DOMContentLoaded', () => {
+  // Only record a proper view after a few seconds has passed
+  setTimeout(recordView, 2000)
+});
+
+

I named my little started script littleBrother.js as a call back to Big Brother. It's just not quite as bad.

+

First, we:

+ +

Recording the View

+

To properly handle the view and the associated data we'll collect later, I'm going to stuff all this information into a simple class.

+
// littleBrother.js
+
+class View {
+  constructor () {
+    this.timestamp = new Date();
+  }
+}
+
+

we'll add a few more fields to this class later.

+

Now that we have a container to hold our view, lets actually record the view.

+
// littleBrother.js
+
+function recordView () {
+  console.log('View recorded.');
+
+  // Construct the view
+  let view = new View();
+}
+

It's that simple. After our timer from above elapses, call this function, who creates the View object.

+

Gathering More Information

+

I want this information to be anonymous, but I still want some more basic information. Let's also gather:

+ +

So far, we've had it really easy: just construct a new object and get it ready to send off the server so that a "view" is recorded. Let's take it a step further.

+

Gathering the OS

+

I did some local testing and had mixed results using some of the web APIs available in vanilla Javascript, so I came up with this:

+

+// Grabbing the operating system with some basic error handling
+  let navigatorData = navigator.userAgentData;
+  let platform;
+  if (!navigatorData) {
+    console.log('userAgentData not available. Using navigator.')
+    navigatorData = navigator;
+    platform = navigator.oscpu;
+    if (!platform) {
+      platform = 'Unknown';
+    }
+  } else {
+    platform = navigatorData.platform;
+  }
+
+

First, we attempt to grab the userAgentData object. Sometimes, though, I found this value to be undefined when testing on various browsers. We'll do a bit of error checking here:

+
    +
  1. See if the truthiness value of the navigatorData variable is false
  2. +
  3. If it is false, resort to using the regular navigator object
  4. +
  5. Attempt to gather the OS information from the (deprecated) oscpu value.
  6. +
  7. Finally, if this also failed, just set the OS to "unknown"
  8. +
+

If the truthiness value of navigatorData is true, then we know that the userAgentData is available to us, so we can just call the platform property.

+

I'm almost positive there are better, more comprehensive ways to accomplish this, but this has worked for me so far. Let's adjust our View class.

+
class View {
+  constructor () {
+    this.timestamp = new Date();
+    this.platform;
+  }
+}
+

Now, we can set this property.

+
// littleBrother.js
+
+function recordView () {
+
+  console.log('View recorded.');
+  console.log(navigator.appName);
+
+  // Grabbing the operating system with some basic error handling
+  let navigatorData = navigator.userAgentData;
+  let platform;
+  if (!navigatorData) {
+    console.log('userAgentData not available. Using navigator.')
+    navigatorData = navigator;
+
+    platform = navigator.oscpu;
+    if (!platform) {
+      platform = 'Unknown';
+    }
+  } else {
+    platform = navigatorData.platform;
+  }
+
+  // Construct the view and get it ready for transport
+  let view = new View();
+  view.platform = platform;
+}
+
+

Gathering URL Information

+

This part is super easy, but super important to accurately track page views. Since we already constructed our View object earlier, and I don't have to do much extra work here, I'm going to add and directly set some new properties on my View class.

+
class View {
+  constructor () {
+    this.timestamp = new Date();
+    this.platform;
+    this.path;
+    this.site;
+    this.fullURL;
+  }
+}
+

Now we simply set the values like so in the recordView function.

+
// littleBrother.js
+
+function recordView () {
+  // Let the unload script know that this isn't a bounce visit
+  bounceVisit = false
+
+  console.log('View recorded.');
+  console.log(navigator.appName);
+
+  // Grabbing the operating system with some basic error handling
+  let navigatorData = navigator.userAgentData;
+  let platform;
+  if (!navigatorData) {
+    console.log('userAgentData not available. Using navigator.')
+    navigatorData = navigator;
+
+    platform = navigator.oscpu;
+    if (!platform) {
+      platform = 'Unknown';
+    }
+  } else {
+    platform = navigatorData.platform;
+  }
+
+  // Construct the view and get it ready for transport
+  let view = new View();
+   view.platform = platform;
++  view.path = window.location.pathname;
++  view.site = window.location.origin;
++  view.fullURL = window.location.href;
+}
+
+

That's it! We now have some basic stats that are indeed anonymous.

+

That's All For Now

+

We now have some decent information that we can record in a datastore. That's all we'll do for now, as we'll need to actually start designing our system next, and recruit some help from our friendly cloud compute providers.

+

A Note for the Snoopy Among My Dear Readers

+

This file is not being distributed with the site just yet, so don't go looking for it! I want to have the system in place before taking up your bandwidth with an extra HTTP request.

+
+ + + + diff --git a/projects/index.html b/projects/index.html index 8286167..74219fe 100644 --- a/projects/index.html +++ b/projects/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm diff --git a/robots/test-ai-post/index.html b/robots/test-ai-post/index.html index 7f8f24c..5674ea2 100644 --- a/robots/test-ai-post/index.html +++ b/robots/test-ai-post/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm diff --git a/tools/index.html b/tools/index.html index 9f82996..847b4af 100644 --- a/tools/index.html +++ b/tools/index.html @@ -14,7 +14,7 @@ rel="stylesheet" /> - + Failed Algorithm