Browse Source

Remade for ham-website

master
Levi Olson 9 months ago
parent
commit
c6b1f3a9c2
20 changed files with 21 additions and 913 deletions
  1. +1
    -1
      app.js
  2. +0
    -129
      posts/basic-http-routing-in-golang.html
  3. +0
    -9
      posts/basic-http-routing-in-golang.json
  4. +0
    -174
      posts/basic-http-routing-in-golang.md
  5. +0
    -69
      posts/bnp-changelog.html
  6. +0
    -9
      posts/bnp-changelog.json
  7. +0
    -98
      posts/bnp-changelog.md
  8. +0
    -24
      posts/chrome-ext-better-network-panel.html
  9. +0
    -9
      posts/chrome-ext-better-network-panel.json
  10. +0
    -35
      posts/chrome-ext-better-network-panel.md
  11. +0
    -133
      posts/i-can-crack-your-password.html
  12. +0
    -9
      posts/i-can-crack-your-password.json
  13. +0
    -4
      posts/something-decent.html
  14. +0
    -9
      posts/something-decent.json
  15. +0
    -79
      posts/vanilla-js-basics.html
  16. +0
    -9
      posts/vanilla-js-basics.json
  17. +0
    -84
      posts/vanilla-js-basics.md
  18. +2
    -12
      views/pages/about.html
  19. +12
    -8
      views/pages/index.ejs
  20. +6
    -9
      views/partials/header.ejs

+ 1
- 1
app.js View File

@ -109,7 +109,7 @@ app.get('/bnp/changelog', (req, res) => {
return res.render('pages/post', postData) return res.render('pages/post', postData)
}) })
const port = 3000
const port = 5000
app.listen(port, () => console.log('Example app listening on port ' + port + '!')) app.listen(port, () => console.log('Example app listening on port ' + port + '!'))
module.exports = app module.exports = app

+ 0
- 129
posts/basic-http-routing-in-golang.html View File

@ -1,129 +0,0 @@
<h1 id="basichttproutingingolang">Basic HTTP Routing in Golang</h1>
<p>Golang is incredibly powerful. Its standard library has so much to offer, but I think other languages have encouraged the use of external libraries for even the most basic tasks. For example, with JavaScript, most inexperienced developers seem to use jQuery to do simple tasks like selecting an element and replacing its contents. When you and I both know jQuery is way overkill for such a task. <a href="https://leviolson.com/posts/vanilla-js-basics">See my article on Vanilla JS basics</a>.</p>
<p>I believe that in order to be considered an expert in a language, you must at least be able to demonstrate using the core language to achieve your goal. In our current case, HTTP routing. Now to be clear, I don't think you need to write everything from scratch all the time, but you should have a firm grasp on what is available by the core language, and when you are better suited to use an external library. If you are looking for more advanced HTTP routing, then I would suggest using something like <a href="https://github.com/gin-gonic/gin">gin</a>.</p>
<p>Enough ranting, let's get to it.</p>
<h2 id="assumptions">Assumptions</h2>
<p>I assume you have basic knowledge of the Go language at this point, so if not, it might be worth searching for some entry level basics first. See <a href="https://tour.golang.org">A Tour of Go</a>.</p>
<h2 id="letsbegin">Let's begin</h2>
<p>The accompanying repo for the code produced in this article is located <a href="https://github.com/leothelocust/basic-http-routing-in-golang">on github</a>.</p>
<h3 id="step1">Step 1</h3>
<p>Here is our basic folder structure for this basic http routing example:</p>
<pre><code> basic-http-routing-in-golang/
main.go
</code></pre>
<p>As a starting point our <code>main.go</code> file looks like this:</p>
<pre class="prettyprint"><code> package main
import (
"fmt"
_ "net/http"
)
func main() {
fmt.Println("Hello HTTP")
}
</code></pre>
<h3 id="step2">Step 2</h3>
<p>Now starting at a very basic level, we can leverage the <a href="https://golang.org/pkg/net/http/#HandleFunc"><code>http.HandleFunc</code></a> method.</p>
<p>It is very simple to use and its signature is easy to understand.</p>
<pre class="prettyprint"><code class="language-go"> func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
</code></pre>
<p>Which basically means, <code class="prettyprint">http.HandleFunc("/url", routingFunction)</code> where <code>routingFunction</code> looks like this:</p>
<pre class="prettyprint"><code class="language-go"> func routingFunction(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
</code></pre>
<p>With <code>fmt.Fprint()</code> we can pass an <code>http.ResponseWriter</code> and a message to display. Our browser will now look like this when we visit the <code>/url</code> endpoint.</p>
<p><img src="https://leviolson.com/images/step2-browser-output.png" alt="Browser Output for Step 2 - Hello HTTP" /></p>
<p>Here is what <code>main.go</code> looks like at this point:</p>
<pre class="prettyprint"><code class="language-go"> package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/hello", helloHTTP)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func helloHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
</code></pre>
<p>Now we could stop there, as this is a "basic" http routing example, but I think it isn't quite useful as an example yet, until we start to see something slightly more practical.</p>
<h3 id="step3">Step 3</h3>
<p>So let's add a <code>NotFound</code> page when we don't match a pattern in <code>HandleFunc</code>. It's as simple as:</p>
<pre class="prettyprint"><code class="language-go"> func notFound(w http.ResponseWriter, req *http.Request) {
http.NotFound(w, req)
}
</code></pre>
<p>Here is what <code>main.go</code> looks like after that:</p>
<pre class="prettyprint"><code class="language-go"> package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/hello", helloHTTP)
http.HandleFunc("/", notFound)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func helloHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
func notFound(w http.ResponseWriter, req *http.Request) {
http.NotFound(w, req)
}
</code></pre>
<p>This will match <code>/hello</code> and use the <code>HelloHTTP</code> method to print "Hello HTTP" to the browser. Any other URLs will get caught by the <code>/</code> pattern and be given the <code>http.NotFound</code> response to the browser.</p>
<p>So that works, but I think we can go further.</p>
<h3 id="step4">Step 4</h3>
<p>We need to give ourselves something more specific than the simple contrived <code>/hello</code> endpoint above. So let's assume we are needing to get a user profile. We will use the url <code>/user/:id</code> where <code>:id</code> is an identifier used to get the user profile from our persistance layer (i.e. our database).</p>
<p>We'll start by creating a new method for this GET request called <code>userProfile</code>:</p>
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) {
userID := req.URL.Path[len("/user/"):]
fmt.Fprintf(w, "User Profile: %q", userID)
}
</code></pre>
<p>Notice that we get the URL from the <code>req</code> variable and we treat the string returned from <code>req.URL.Path</code> as a byte slice to get everything after the <code>/user/</code> in the string. <strong>Note: this isn't fool proof, <code>/user/10ok</code> would get matched here, and we would be assigning <code>userID</code> to <code>"10ok"</code>.</strong></p>
<p>Let's add this new route in our <code>main</code> function:</p>
<pre class="prettyprint"><code class="language-go"> func main() {
http.HandleFunc("/hello", helloHTTP)
http.HandleFunc("/user/", userProfile)
http.HandleFunc("/", notFound)
log.Fatal(http.ListenAndServe(":8080", nil))
}
</code></pre>
<p><em>Note: that this pattern <code>/user/</code> matches the trailing <code>/</code> so that a call to <code>/user</code> in the browser would return a <code>404 Not Found</code>.</em></p>
<h3 id="step5">Step 5</h3>
<p>Ok, so we have introduced some pretty severe holes in the security of our new HTTP router. As mentioned in a note above, treating the <code>req.URL.Path</code> as a byte slice and just taking the last half is a terrible idea. So let's fix this:</p>
<pre class="prettyprint"><code class="language-go"> var validPath = regexp.MustCompile("^/(user)/([0-9]+)$")
func getID(w http.ResponseWriter, req *http.Request) (string, error) {
m := validPath.FindStringSubmatch(req.URL.Path)
if m == nil {
http.NotFound(w, req)
return "", errors.New("Invalid ID")
}
return m[2], nil // The ID is the second subexpression.
}
</code></pre>
<p>Now we can use this method in our code:</p>
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) {
userID, err := getID(w, req)
if err != nil {
return
}
fmt.Fprintf(w, "User Profile: %q", userID)
}
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>For now, I'm calling this "Basic HTTP Routing in Golang" article finished. But I do plan to add more to it as time allows. Additionally, I'd like to create a more advanced article that discusses the ability to respond to not only GET requests, but also POST, PUT, and DELETE HTTP methods. Look for an "Advanced HTTP routing in Golang" article in the future. Thanks for reading this far. I wish you well in your Go endeavors.</p>

+ 0
- 9
posts/basic-http-routing-in-golang.json View File

@ -1,9 +0,0 @@
{
"title": "Basic HTTP Routing in Golang - Levi Olson",
"permalink": "/posts/basic-http-routing-in-golang",
"created_at": "2018-05-09T11:52:50-06:00",
"created_at_short": "2018-05-09",
"post_title": "basic http routing in golang",
"active": "posts",
"content_file": "basic-http-routing-in-golang.html"
}

+ 0
- 174
posts/basic-http-routing-in-golang.md View File

@ -1,174 +0,0 @@
# Basic HTTP Routing in Golang #
Golang is incredibly powerful. Its standard library has so much to offer, but I think other languages have encouraged the use of external libraries for even the most basic tasks. For example, with JavaScript, most inexperienced developers seem to use jQuery to do simple tasks like selecting an element and replacing its contents. When you and I both know jQuery is way overkill for such a task. [See my article on Vanilla JS basics](https://leviolson.com/posts/vanilla-js-basics).
I believe that in order to be considered an expert in a language, you must at least be able to demonstrate using the core language to achieve your goal. In our current case, HTTP routing. Now to be clear, I don't think you need to write everything from scratch all the time, but you should have a firm grasp on what is available by the core language, and when you are better suited to use an external library. If you are looking for more advanced HTTP routing, then I would suggest using something like [gin](https://github.com/gin-gonic/gin).
Enough ranting, let's get to it.
## Assumptions ##
I assume you have basic knowledge of the Go language at this point, so if not, it might be worth searching for some entry level basics first. See [A Tour of Go](https://tour.golang.org).
## Let's begin ##
The accompanying repo for the code produced in this article is located [on github](https://github.com/leothelocust/basic-http-routing-in-golang).
### Step 1 ###
Here is our basic folder structure for this basic http routing example:
<pre><code> basic-http-routing-in-golang/
main.go
</code></pre>
As a starting point our `main.go` file looks like this:
<pre class="prettyprint"><code> package main
import (
"fmt"
_ "net/http"
)
func main() {
fmt.Println("Hello HTTP")
}
</code></pre>
### Step 2 ###
Now starting at a very basic level, we can leverage the [`http.HandleFunc`](https://golang.org/pkg/net/http/#HandleFunc) method.
It is very simple to use and its signature is easy to understand.
<pre class="prettyprint"><code class="language-go"> func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
</code></pre>
Which basically means, <code class="prettyprint">http.HandleFunc("/url", routingFunction)</code> where `routingFunction` looks like this:
<pre class="prettyprint"><code class="language-go"> func routingFunction(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
</code></pre>
With `fmt.Fprint()` we can pass an `http.ResponseWriter` and a message to display. Our browser will now look like this when we visit the `/url` endpoint.
![Browser Output for Step 2 - Hello HTTP](https://leviolson.com/images/step2-browser-output.png)
Here is what `main.go` looks like at this point:
<pre class="prettyprint"><code class="language-go"> package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/hello", helloHTTP)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func helloHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
</code></pre>
Now we could stop there, as this is a "basic" http routing example, but I think it isn't quite useful as an example yet, until we start to see something slightly more practical.
### Step 3 ###
So let's add a `NotFound` page when we don't match a pattern in `HandleFunc`. It's as simple as:
<pre class="prettyprint"><code class="language-go"> func notFound(w http.ResponseWriter, req *http.Request) {
http.NotFound(w, req)
}
</code></pre>
Here is what `main.go` looks like after that:
<pre class="prettyprint"><code class="language-go"> package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/hello", helloHTTP)
http.HandleFunc("/", notFound)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func helloHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello HTTP")
}
func notFound(w http.ResponseWriter, req *http.Request) {
http.NotFound(w, req)
}
</code></pre>
This will match `/hello` and use the `HelloHTTP` method to print "Hello HTTP" to the browser. Any other URLs will get caught by the `/` pattern and be given the `http.NotFound` response to the browser.
So that works, but I think we can go further.
### Step 4 ###
We need to give ourselves something more specific than the simple contrived `/hello` endpoint above. So let's assume we are needing to get a user profile. We will use the url `/user/:id` where `:id` is an identifier used to get the user profile from our persistance layer (i.e. our database).
We'll start by creating a new method for this GET request called `userProfile`:
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) {
userID := req.URL.Path[len("/user/"):]
fmt.Fprintf(w, "User Profile: %q", userID)
}
</code></pre>
Notice that we get the URL from the `req` variable and we treat the string returned from `req.URL.Path` as a byte slice to get everything after the `/user/` in the string. **Note: this isn't fool proof, `/user/10ok` would get matched here, and we would be assigning `userID` to `"10ok"`.**
Let's add this new route in our `main` function:
<pre class="prettyprint"><code class="language-go"> func main() {
http.HandleFunc("/hello", helloHTTP)
http.HandleFunc("/user/", userProfile)
http.HandleFunc("/", notFound)
log.Fatal(http.ListenAndServe(":8080", nil))
}
</code></pre>
_Note: that this pattern `/user/` matches the trailing `/` so that a call to `/user` in the browser would return a `404 Not Found`._
### Step 5 ####
Ok, so we have introduced some pretty severe holes in the security of our new HTTP router. As mentioned in a note above, treating the `req.URL.Path` as a byte slice and just taking the last half is a terrible idea. So let's fix this:
<pre class="prettyprint"><code class="language-go"> var validPath = regexp.MustCompile("^/(user)/([0-9]+)$")
func getID(w http.ResponseWriter, req *http.Request) (string, error) {
m := validPath.FindStringSubmatch(req.URL.Path)
if m == nil {
http.NotFound(w, req)
return "", errors.New("Invalid ID")
}
return m[2], nil // The ID is the second subexpression.
}
</code></pre>
Now we can use this method in our code:
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) {
userID, err := getID(w, req)
if err != nil {
return
}
fmt.Fprintf(w, "User Profile: %q", userID)
}
</code></pre>
## Conclusion ##
For now, I'm calling this "Basic HTTP Routing in Golang" article finished. But I do plan to add more to it as time allows. Additionally, I'd like to create a more advanced article that discusses the ability to respond to not only GET requests, but also POST, PUT, and DELETE HTTP methods. Look for an "Advanced HTTP routing in Golang" article in the future. Thanks for reading this far. I wish you well in your Go endeavors.

+ 0
- 69
posts/bnp-changelog.html View File

@ -1,69 +0,0 @@
<h1 id="betternetworkpanelchangelog">Better Network Panel - Changelog</h1>
<ul>
<li><a href="#version-101">Version 1.0.1</a>
<ul>
<li><a href="#panel-settings">Panel Settings</a></li>
</ul>
</li>
<li><a href="#version-100">Version 1.0.0</a>
<ul>
<li><a href="#improved-search">Improved Search</a></li>
<li><a href="#json-editor-built-in">JSON Editor BUILT IN</a></li>
<li><a href="#vertical-chrome-panel">Vertical Chrome Panel</a></li>
<li><a href="#download-json">Download JSON</a></li>
</ul>
</li>
</ul>
<p><a id="version-101"></a></p>
<h2 id="version101">Version 1.0.1</h2>
<p><a id="panel-settings"></a></p>
<h3 id="panelsettings">Panel Settings</h3>
<p>A new panel has been added that contains some configurable items.</p>
<p><a href="/images/v1.0.1-Panel-Settings.png" data-jbox-image="gallery">
<img src="/images/v1.0.1-Panel-Settings.png" alt="Version 1.0.1 Panel Settings" />
</a></p>
<h3 id="variousbugfixesandenhancements">Various Bugfixes and Enhancements</h3>
<ul>
<li>SCSS refactor for better handling of page size changes (i.e. using flexbox)</li>
<li>User can enable/disable auto-scrolling of network logs (See <a href="#panel-settings">Panel Settings</a>)</li>
<li>Search terms now have better CSS cursor indicators</li>
</ul>
<p><a id="version-100"></a></p>
<h2 id="version100">Version 1.0.0</h2>
<p><a href="/images/v1.0.0-FullScreenshot.png" data-jbox-image="gallery">
<img src="/images/v1.0.0-FullScreenshot.png" alt="Version 1.0.0 Screenshot" />
</a></p>
<p><a id="improved-search"></a></p>
<h3 id="improvedsearch">Improved Search</h3>
<p>Advanced search capability has been added in this release which improves on the previous search by adding a negation search (i.e. "-carts" which would remove requests containing "carts" in the results).</p>
<p><a href="/images/v1.0.0-Search.png" data-jbox-image="gallery">
<img src="/images/v1.0.0-Search.png" alt="New Improved Search Screenshot" />
</a></p>
<p>Additionally, <strong>AND</strong> and <strong>OR</strong> searching filters have been added. So you can search for:</p>
<blockquote>
<p><code>products</code> <strong>AND</strong> <code>services</code></p>
</blockquote>
<p>Which would return any request containing <strong>BOTH</strong> <code>products</code> <strong>AND</strong> <code>services</code> somewhere in the headers, request body, etc…</p>
<p>And you can search for:</p>
<blockquote>
<p><code>products</code> <strong>OR</strong> <code>services</code></p>
</blockquote>
<p>Which would return any requests containing <strong>EITHER</strong> <code>products</code> <strong>OR</strong> <code>services</code>.</p>
<p><a id="json-editor-built-in"></a></p>
<h3 id="jsoneditorbuiltin">JSON Editor BUILT IN</h3>
<p>Using the Open Source <a href="https://github.com/josdejong/jsoneditor">JSON Editor</a>, you can now easily search and view JSON data just as you can on the official <a href="https://jsoneditoronline.org">jsoneditoronline.org</a> website.</p>
<p><a href="/images/v1.0.0-JSONEditor.png" data-jbox-image="gallery">
<img src="/images/v1.0.0-JSONEditor.png" alt="JSON Editor Screenshot" />
</a></p>
<p><a id="vertical-chrome-panel"></a></p>
<h3 id="verticalchromepanel">Vertical Chrome Panel</h3>
<p>Better Network Panel now supports a vertical layout using responsive CSS. Panel resizing will be released soon.</p>
<p><a href="/images/v1.0.0-VerticalPanel.png" data-jbox-image="gallery">
<img src="/images/v1.0.0-VerticalPanel.png" alt="Vertical Panel Screenshot" />
</a></p>
<p><a id="download-json"></a></p>
<h3 id="downloadjson">Download JSON</h3>
<p>Download the current panel as a JSON doc.</p>
<p><a href="/images/v1.0.0-DownloadJSON.png" data-jbox-image="gallery">
<img src="/images/v1.0.0-DownloadJSON.png" alt="Download JSON Button Screenshot" />
</a></p>

+ 0
- 9
posts/bnp-changelog.json View File

@ -1,9 +0,0 @@
{
"title": "Better Network Panel - Changelog - Levi Olson",
"permalink": "/posts/bnp-changelog",
"created_at": "2021-01-23T10:05:19-06:00",
"created_at_short": "2021-01-23",
"post_title": "Better Network Panel - Changelog",
"active": "",
"content_file": "bnp-changelog.html"
}

+ 0
- 98
posts/bnp-changelog.md View File

@ -1,98 +0,0 @@
# Better Network Panel - Changelog
<ul>
<li><a href="#version-101">Version 1.0.1</a>
<ul>
<li><a href="#panel-settings">Panel Settings</a></li>
</ul>
</li>
<li><a href="#version-100">Version 1.0.0</a>
<ul>
<li><a href="#improved-search">Improved Search</a></li>
<li><a href="#json-editor-built-in">JSON Editor BUILT IN</a></li>
<li><a href="#vertical-chrome-panel">Vertical Chrome Panel</a></li>
<li><a href="#download-json">Download JSON</a></li>
</ul>
</li>
</ul>
<a id="version-101"></a>
## Version 1.0.1
<a id="panel-settings"></a>
### Panel Settings
A new panel has been added that contains some configurable items.
<a href="/images/v1.0.1-Panel-Settings.png" data-jbox-image="gallery">
![Version 1.0.1 Panel Settings](/images/v1.0.1-Panel-Settings.png)
</a>
### Various Bugfixes and Enhancements
* SCSS refactor for better handling of page size changes (i.e. using flexbox)
* User can enable/disable auto-scrolling of network logs (See [Panel Settings](#panel-settings))
* Search terms now have better CSS cursor indicators
<a id="version-100"></a>
## Version 1.0.0
<a href="/images/v1.0.0-FullScreenshot.png" data-jbox-image="gallery">
![Version 1.0.0 Screenshot](/images/v1.0.0-FullScreenshot.png)
</a>
<a id="improved-search"></a>
### Improved Search
Advanced search capability has been added in this release which improves on the previous search by adding a negation search (i.e. "-carts" which would remove requests containing "carts" in the results).
<a href="/images/v1.0.0-Search.png" data-jbox-image="gallery">
![New Improved Search Screenshot](/images/v1.0.0-Search.png)
</a>
Additionally, **AND** and **OR** searching filters have been added. So you can search for:
> `products` **AND** `services`
Which would return any request containing **BOTH** `products` **AND** `services` somewhere in the headers, request body, etc...
And you can search for:
> `products` **OR** `services`
Which would return any requests containing **EITHER** `products` **OR** `services`.
<a id="json-editor-built-in"></a>
### JSON Editor BUILT IN
Using the Open Source [JSON Editor](https://github.com/josdejong/jsoneditor), you can now easily search and view JSON data just as you can on the official [jsoneditoronline.org](https://jsoneditoronline.org) website.
<a href="/images/v1.0.0-JSONEditor.png" data-jbox-image="gallery">
![JSON Editor Screenshot](/images/v1.0.0-JSONEditor.png)
</a>
<a id="vertical-chrome-panel"></a>
### Vertical Chrome Panel
Better Network Panel now supports a vertical layout using responsive CSS. Panel resizing will be released soon.
<a href="/images/v1.0.0-VerticalPanel.png" data-jbox-image="gallery">
![Vertical Panel Screenshot](/images/v1.0.0-VerticalPanel.png)
</a>
<a id="download-json"></a>
### Download JSON
Download the current panel as a JSON doc.
<a href="/images/v1.0.0-DownloadJSON.png" data-jbox-image="gallery">
![Download JSON Button Screenshot](/images/v1.0.0-DownloadJSON.png)
</a>

+ 0
- 24
posts/chrome-ext-better-network-panel.html View File

@ -1,24 +0,0 @@
<h1 id="betternetworkpanelachromeextension">Better Network Panel - a Chrome extension</h1>
<blockquote>
<p>"As a Salesforce and Vlocity developer, I'm constantly looking for ways to improve my workflow, speed up my debugging, and find answers fast."</p>
</blockquote>
<h2 id="theproblem">THE PROBLEM</h2>
<p>Over the last couple months, part of my debugging process has involved using the Chrome DevTools "Network" panel to find a specific <code>apexremote</code> call. The search to find one <code>apexremote</code> call out of dozens has been… annoying. </p>
<p>The page loads, several dozen <code>apexremote</code> calls flood the panel, and I start clicking each one, until the correct one (i.e. <code>Request-Body</code> contains "xyz") and I can proceed to look at the Preview.</p>
<p>The issue has only just begun, as I need to inspect the <code>Response</code>, perform some searches for <code>ID</code>s and the like, and although the <code>Response</code> is JSON format, the node in the response I need to search is stringified in a child member. So I must copy the data, parse it somehow, either locally on my machine or on the web (jsoneditoronline.org has been great) and finally perform the searching I need.</p>
<p>And all of the above is done several times a day.</p>
<h2 id="thesolution">THE SOLUTION</h2>
<p><a href="https://chrome.google.com/webstore/detail/better-network-panel/kknnkgpbclaljhfcknhbebhppmkmoaml"><img src="/images/bnpscreenshot.png" alt="BNP for Chrome" /></a></p>
<p>I present to you a <a href="https://chrome.google.com/webstore/detail/better-network-panel/kknnkgpbclaljhfcknhbebhppmkmoaml">Better Network Panel</a>. A Chrome extension that adds a new panel, and offers great features like:</p>
<ul>
<li><strong>Full Search</strong> - Entire request is searchable (i.e. headers, request body, etc…), not just URI</li>
<li><strong>JSON Parsing</strong> - Even nested members that contain stringified JSON are parsed to 3 levels deep</li>
<li><strong>JSON Search</strong> - Incremental searching is available directly in the Preview pane</li>
<li><strong>Regex Search</strong> - Powerfull regex searches can be performed on the Preview pane</li>
<li>More to come</li>
</ul>
<h2 id="opensourcebaby">Open source baby</h2>
<p>View it on <a href="https://github.com/leothelocust/better-network-chrome-panel">GitHub</a></p>
<h2 id="specialthanks">Special Thanks</h2>
<p>A huge thanks and recognition goes to <a href="https://github.com/milton-lai/saml-chrome-panel">Milton Lai</a> and his project SAML Chrome Panel. I started from a fork of his project, but later started fresh as there was a lot of SAML specific code that this project doesn't use/need. The UI is nearly identical, but the code underneath has become fairly different at this point.</p>
<p>The SAML Chrome Panel was a huge help and ispiration! Thank you Milton and contributors to the SAML Chrome Panel project!</p>

+ 0
- 9
posts/chrome-ext-better-network-panel.json View File

@ -1,9 +0,0 @@
{
"title": "Better Network Panel - a Chrome Extension - Levi Olson",
"permalink": "/posts/chrome-ext-better-network-panel",
"created_at": "2020-10-04T17:55:13-33:00",
"created_at_short": "2020-10-04",
"post_title": "better network panel - a chrome extension",
"active": "posts",
"content_file": "chrome-ext-better-network-panel.html"
}

+ 0
- 35
posts/chrome-ext-better-network-panel.md View File

@ -1,35 +0,0 @@
# Better Network Panel - a Chrome extension
> "As a Salesforce and Vlocity developer, I'm constantly looking for ways to improve my workflow, speed up my debugging, and find answers fast."
## THE PROBLEM
Over the last couple months, part of my debugging process has involved using the Chrome DevTools "Network" panel to find a specific `apexremote` call. The search to find one `apexremote` call out of dozens has been... annoying.
The page loads, several dozen `apexremote` calls flood the panel, and I start clicking each one, until the correct one (i.e. `Request-Body` contains "xyz") and I can proceed to look at the Preview.
The issue has only just begun, as I need to inspect the `Response`, perform some searches for `ID`s and the like, and although the `Response` is JSON format, the node in the response I need to search is stringified in a child member. So I must copy the data, parse it somehow, either locally on my machine or on the web (jsoneditoronline.org has been great) and finally perform the searching I need.
And all of the above is done several times a day.
## THE SOLUTION
[![BNP for Chrome](/images/bnpscreenshot.png)](https://chrome.google.com/webstore/detail/better-network-panel/kknnkgpbclaljhfcknhbebhppmkmoaml)
I present to you a [Better Network Panel](https://chrome.google.com/webstore/detail/better-network-panel/kknnkgpbclaljhfcknhbebhppmkmoaml). A Chrome extension that adds a new panel, and offers great features like:
* **Full Search** - Entire request is searchable (i.e. headers, request body, etc...), not just URI
* **JSON Parsing** - Even nested members that contain stringified JSON are parsed to 3 levels deep
* **JSON Search** - Incremental searching is available directly in the Preview pane
* **Regex Search** - Powerfull regex searches can be performed on the Preview pane
* More to come
## Open source baby
View it on [GitHub](https://github.com/leothelocust/better-network-chrome-panel)
## Special Thanks
A huge thanks and recognition goes to [Milton Lai](https://github.com/milton-lai/saml-chrome-panel) and his project SAML Chrome Panel. I started from a fork of his project, but later started fresh as there was a lot of SAML specific code that this project doesn't use/need. The UI is nearly identical, but the code underneath has become fairly different at this point.
The SAML Chrome Panel was a huge help and ispiration! Thank you Milton and contributors to the SAML Chrome Panel project!

+ 0
- 133
posts/i-can-crack-your-password.html View File

@ -1,133 +0,0 @@
<p>You may think your password is secure. Maybe you have chosen an obscure word, mixed in numbers, and added a
<code>!</code> to the end. Think you’re pretty safe, huh?</p>
<p>The truth is, you aren’t. I can crack a 5 character password in less then 139 seconds!</p>
<p>We have been trained over time, by
<em>unproven</em> security techniques, to make our passwords contain numbers and letters; sometimes even an
<code>@</code> or
<code>#</code> or
<code>!</code> is added to the mix.
<strong>But</strong> the truth is, we are only making it harder on ourselves with passwords that are difficult to remember, but
easy to guess in a brute-force attack (automated hacking software).</p>
<p>Although a 128-character
<em>totally random</em> password would be phenomenal, 8 characters is about all that can be enforced without frustrating
users. However, an 8-character password comprised of uppercase, lowercase, and numbers can be cracked overnight in a
real world brute-force attack.</p>
<h2 id="the-scoop-on-alpha-numeric-passwords">The Scoop on Alpha-Numeric Passwords</h2>
<p>Even though we are trained to think that a password of
<code>Blu3D0g5</code> is the most secure type of password, it can still be cracked by a brute-force attack.
</p>
<p>Bare with me while I explain…
<em>with some maths!</em>
</p>
<p>For every character in an alpha-numeric password there are
<code>62</code> possibilities. First, you have the
<code>26</code> character alphabet in lowercase, then
<code>26</code> more in uppercase, and
<code>10</code> digits.</p>
<div>
<pre style="text-align: center;"><code>26 + 26 + 10 = 62</code></pre>
</div>
<p>This is to say that if you choose 8 characters,
<em>completely at random</em>, your password would be very secure. However, we typically take a familiar word, or couple
of words, and add some uppercase letters, or replace
<code>e</code> with
<code>3</code>, etc… which is
<strong>not</strong> secure.</p>
<p>When we calculate the Information Entropy (known as the lack of order or predictability) we can see that a completely random
character set is great, but when it is derived from an English word, or contains a date, it is simply terrible. The equation
looks like this:</p>
<div>
<pre style="text-align: center;"><code>[Password_Length] * log2([Number_of_Possibilities]) = "Information Entropy"</code></pre>
</div>
<div>
<pre><code>8 * log2(62) = "~48 bits"
# which would take almost 9,000 years at 1,000 guesses per second</code></pre>
</div>
<p>
<em>But, when your password isn’t
<strong>completely</strong> random, it’s not that simple.</em>
</p>
<p>Because the password we chose was actually two words,
<code>blue</code> and
<code>dogs,</code> with some uppercase and numbers mixed in, the total Entropy is
<strong>MUCH</strong> less. Something closer to
<code>~28 bits</code>.</p>
<p>
<strong>So let’s calculate what this actually means.</strong> A brute-force attacker can easily guess 1,000 times per second.
The total number of options to guess can be calculated by taking the base 2 to the total number of bits.</p>
<div>
<pre><code>2^28 = 268,435,456
# This is the total number of possibilities the password could be.</code></pre>
</div>
<p>In theory though, an attacker only needs to guess about half the total number of options before stumbling upon the correct
one. So:</p>
<div>
<pre><code>268,435,456 / 2 = 134,217,728
# Total number of guesses it takes to guess your password
134,217,728 / 1,000 = ~134,218
# At 1,000 guesses per second, it takes about 134,218 seconds
134,218 / 60 = ~2,237
# Or 2,237 minutes
2,237 / 60 = ~37
# Or 37 hours to guess your password</code></pre>
</div>
<hr>
<h2 id="in-contrast">In Contrast</h2>
<p>Let’s say we use 4
<strong>random</strong> words, without any numbers, and all lowercase. For example:
<code>yellow</code>
<code>tiger</code>
<code>note</code>
<code>basket</code>. There are an incalculable amount of words for you to choose from, but most likely, you will choose from
about 7,000 of the most commonly used words. If you use unique words like
<code>laggardly</code> or
<code>pomological</code>, the total time to crack your password will increase
<strong>exponentially</strong>!</p>
<p>Using this new data, the Information Entropy is now calculated as:</p>
<div>
<pre style="text-align: center;"><code>[Number_of_words] * log2(7,000)</code></pre>
</div>
<p>So, this new password now has
<code>~51 bits</code> of Entropy, and using the same time calculations above, we estimate our password would take about
<code>35,702 years</code> to crack at the rate of 1,000 guesses per second.</p>
<p>That is in stark contrast to the short 37 hours it takes to crack the
<code>Blu3D0g5</code> password.</p>
<hr>
<h2 id="the-take-away">The Take Away</h2>
<p>By simply increasing the length of our passwords and using words randomly mixed together, we can have the most secure passwords
that attackers will struggle to figure out, but that we can actually remember. I personally will never forget
<code>yellow</code>
<code>tiger</code>
<code>note</code>
<code>basket</code> as long as I live. However, now I can’t use it.</p>

+ 0
- 9
posts/i-can-crack-your-password.json View File

@ -1,9 +0,0 @@
{
"title": "I can crack your password - Levi Olson",
"permalink": "/posts/i-can-crack-your-password",
"created_at": "2018-04-27T07:05:32-06:00",
"created_at_short": "2018-04-27",
"post_title": "i can crack your password",
"active": "posts",
"content_file": "i-can-crack-your-password.html"
}

+ 0
- 4
posts/something-decent.html View File

@ -1,4 +0,0 @@
<blockquote>
<p>the start of something... decent</p>
</blockquote>
<p>I don't expect to have a lot to say, but when I do, I'd like a place to put it.</p>

+ 0
- 9
posts/something-decent.json View File

@ -1,9 +0,0 @@
{
"title": "Something Decent - Levi Olson",
"permalink": "/posts/something-decent",
"created_at": "2018-04-27T05:05:19-06:00",
"created_at_short": "2018-04-27",
"post_title": "the start of something... decent",
"active": "posts",
"content_file": "something-decent.html"
}

+ 0
- 79
posts/vanilla-js-basics.html View File

@ -1,79 +0,0 @@
<h1 id="vanilla-js-basics">Vanilla JS Basics</h1>
<p>
<em>Warning: This article turned out to be a bit of rant. So if you are the type to get offended when I say negative things
about JavaScript, you are welcome to leave.</em>
</p>
<p>JavaScript is what I consider to be an &quot;easy&quot; language. Now what do I mean by that? Well, its usually the first
<em>scripting</em> language that new developers learn, and you can get started with very little &quot;training&quot;. It
has a relatively simple syntax. It can be very powerful. So from my point of view, its an easy language to pick up. And
therein lies the problem.</p>
<p>So many of the JavaScript programmers out there today hear the term &quot;JavaScript&quot; and think in there mind &quot;jQuery&quot;.
Now that's great to have that kind of brand recognition if you are jQuery, but if you are looking to be an efficient
programmer that doesn't put holes in everything you make, you may want to consider that JavaScript is NOT jQuery.</p>
<p>Additionally, we need to start thinking about the consequences of using third-party libraries for everything. Longer load
times, additional security risks, more memory consumption, and the list goes on.</p>
<p>I want to give you at least a few little snippets of vanilla JavaScript that will get you on your way to not importing jQuery
on every project as a
<em>step 1</em>. It should be near the end of your steps and only as needed.</p>
<p>
<em>Disclaimer: Vanilla JavaScript will be longer (i.e. more verbose), but this isn't always a bad thing. Keep in mind that
we are eliminating the import of another package, and all the bloat that comes with it.</em>
</p>
<h2 id="assumptions">Assumptions</h2>
<p>For starters, I'm assuming that you getting this far means that you at least have heard of JavaScript. If you have not heard
of jQuery,
<strong>leave now</strong>, I don't want &quot;introducing someone to jQuery&quot; to be what you get out of this.</p>
<p>Let's begin...</p>
<h3 id="selecting-element-in-the-dom">Selecting Element in the DOM</h3>
<p>jQuery</p>
<pre><code> $('#myID')
</code></pre>
<p>Vanilla JavaScript</p>
<pre><code> document.getElementById('myID')
</code></pre>
<p>Again, note that vanilla JavaScript is longer, but its actually more descriptive of what is going on here. Unless you are
familiar with jQuery (yes, I know you are) the jQuery syntax doesn't tell you what its doing.</p>
<h3 id="replace-text-html-in-the-dom">Replace Text/HTML in the DOM</h3>
<p>jQuery</p>
<pre><code> $('#myID').html('here is the replacement')
</code></pre>
<p>Vanilla JavaScript</p>
<pre><code> document.getElementById('myID').innerHTML('here is the replacement')
</code></pre>
<p>Very similar eh. However, there is actually some performance gain by using vanilla JavaScript. See
<a href="https://stackoverflow.com/questions/3563107/jquery-html-vs-innerhtml#answer-3563136">here</a>.</p>
<h3 id="click-handling-in-the-dom">Click Handling in the DOM</h3>
<p>jQuery</p>
<pre><code> $('#myID').click(function() {
alert('Clicked it!')
})
</code></pre>
<p>Vanilla JavaScript</p>
<pre><code> document.getElementById('myID').addEventListener('click', function(e) {
alert('Clicked it!')
})
</code></pre>
<p>So easy.</p>
<h3 id="advanced-queries-and-iteration">Advanced Queries and Iteration</h3>
<p>jQuery</p>
<pre><code> $('.item').hide()
</code></pre>
<p>Vanilla JavaScript</p>
<pre><code> var items = document.getElementsByClassName('.items')
for (var i = 0; i &lt; items.length; i++) {
item[i].style.display = 'none'
}
</code></pre>
<p>We're starting to see the verbosity I mentioned above, but again, remember that we aren't loading in a massive third-party
library!</p>
<h3 id="even-more-advanced">Even More Advanced</h3>
<p>See Patrick Kunka's article
<a href="https://blog.wearecolony.com/a-year-without-jquery/">A Year Without jQuery</a>
</p>
<p>Patrick and I agree on many of the same points and his article articulates some helper functions that can be used to perform
more advanced loops, child selection and child indexing. I highly recommend you read through his article.</p>
<h2 id="conclusion">Conclusion</h2>
<p>If you find that your requirements heavily rely on JavaScript for DOM manipulation, or that you need animations such as the
ones provided by jQuery, then don't let me stop you. But if you only need some of what was covered above, or you want
to put a priority on performance, then you should really consider going with plain vanilla JavaScript and leave the dependencies
behind. You won't regret it.</p>

+ 0
- 9
posts/vanilla-js-basics.json View File

@ -1,9 +0,0 @@
{
"title": "Vanilla JS Basics - Levi Olson",
"permalink": "/posts/vanilla-js-basics",
"created_at": "2018-05-10T13:33:12-06:00",
"created_at_short": "2018-05-10",
"post_title": "vanilla js basics",
"active": "posts",
"content_file": "vanilla-js-basics.html"
}

+ 0
- 84
posts/vanilla-js-basics.md View File

@ -1,84 +0,0 @@
# Vanilla JS Basics #
_Warning: This article turned out to be a bit of rant. So if you are the type to get offended when I say negative things about JavaScript, you are welcome to leave._
JavaScript is what I consider to be an "easy" language. Now what do I mean by that? Well, its usually the first _scripting_ language that new developers learn, and you can get started with very little "training". It has a relatively simple syntax. It can be very powerful. So from my point of view, its an easy language to pick up. And therein lies the problem.
So many of the JavaScript programmers out there today hear the term "JavaScript" and think in there mind "jQuery". Now that's great to have that kind of brand recognition if you are jQuery, but if you are looking to be an efficient programmer that doesn't put holes in everything you make, you may want to consider that JavaScript is NOT jQuery.
Additionally, we need to start thinking about the consequences of using third-party libraries for everything. Longer load times, additional security risks, more memory consumption, and the list goes on.
I want to give you at least a few little snippets of vanilla JavaScript that will get you on your way to not importing jQuery on every project as a _step 1_. It should be near the end of your steps and only as needed.
_Disclaimer: Vanilla JavaScript will be longer (i.e. more verbose), but this isn't always a bad thing. Keep in mind that we are eliminating the import of another package, and all the bloat that comes with it._
## Assumptions ##
For starters, I'm assuming that you getting this far means that you at least have heard of JavaScript. If you have not heard of jQuery, **leave now**, I don't want "introducing someone to jQuery" to be what you get out of this.
Let's begin...
### Selecting Element in the DOM ###
jQuery
$('#myID')
Vanilla JavaScript
document.getElementById('myID')
Again, note that vanilla JavaScript is longer, but its actually more descriptive of what is going on here. Unless you are familiar with jQuery (yes, I know you are) the jQuery syntax doesn't tell you what its doing.
### Replace Text/HTML in the DOM ###
jQuery
$('#myID').html('here is the replacement')
Vanilla JavaScript
document.getElementById('myID').innerHTML('here is the replacement')
Very similar eh. However, there is actually some performance gain by using vanilla JavaScript. See [here](https://stackoverflow.com/questions/3563107/jquery-html-vs-innerhtml#answer-3563136).
### Click Handling in the DOM ###
jQuery
$('#myID').click(function() {
alert('Clicked it!')
})
Vanilla JavaScript
document.getElementById('myID').addEventListener('click', function(e) {
alert('Clicked it!')
})
So easy.
### Advanced Queries and Iteration ###
jQuery
$('.item').hide()
Vanilla JavaScript
var items = document.getElementsByClassName('.items')
for (var i = 0; i < items.length; i++) {
item[i].style.display = 'none'
}
We're starting to see the verbosity I mentioned above, but again, remember that we aren't loading in a massive third-party library!
### Even More Advanced ###
See Patrick Kunka's article [A Year Without jQuery](https://blog.wearecolony.com/a-year-without-jquery/)
Patrick and I agree on many of the same points and his article articulates some helper functions that can be used to perform more advanced loops, child selection and child indexing. I highly recommend you read through his article.
## Conclusion ##
If you find that your requirements heavily rely on JavaScript for DOM manipulation, or that you need animations such as the ones provided by jQuery, then don't let me stop you. But if you only need some of what was covered above, or you want to put a priority on performance, then you should really consider going with plain vanilla JavaScript and leave the dependencies behind. You won't regret it.

+ 2
- 12
views/pages/about.html View File

@ -45,18 +45,8 @@
<body> <body>
<main> <main>
<p> <p>
Owner of
<a href="https://leviolson.com/">this site</a>,
<br />currently working for
<a href="https://vlocity.com" target="_blank">this company</a>,
<br />former Senior Software Engineer at
<a href="https://carsforsale.com" target="_blank">this company</a>,
<br />look what
<a href="https://github.com/leothelocust" target="_blank">I can do</a>,
<br />contact me
<a href="mailto:me@leviolson.com">here</a>
<br />or read stuff I write
<a href="/posts">here</a>.
Check out my personal webite
<a href="https://leviolson.com/">here</a>
</p> </p>
</main> </main>
</body> </body>

+ 12
- 8
views/pages/index.ejs View File

@ -25,14 +25,18 @@
</div> </div>
</header> </header>
<div class="entry-content"> <div class="entry-content">
<p>So... we've been trying to get our 5 yr old son to finish drinking his milk.</p>
<p>One of the ways we have encouraged him is to explain that milk contains proteins that
are good for the body and help build strong muscles. Skim is good, 1% is good, 2% is even better.
</p>
<p>He thought for a while, and said...<br /><br /></p>
<blockquote><p>"Dad, have you been drinking 100% milk?
<br /> Cause your muscles are sooo big!"</p></blockquote>
<p>And that my friends is why being a dad is the best.</p>
<h2>K0LEO</h2>
<p><a title="Open in new tab" target="_blank" href="https://www.qrz.com/db/K0LEO">Find me on QRZ</a></p>
<p>QRV on DMR. Usually on TG 3146 (South Dakota), but occasionally I check out 31466, 3169, etc.</p>
<p>I got my Technician license in May of 2023, and immediately began tinkering with code plugs and operating in a hyper-local context with UHF/VHF and close friends that just started as well. One of my main reasons for getting licensed was to begin teaching/instructing some tactical comms courses at [OpenRangeTraining.com](http://OpenRangeTraining.com) over the course of the next year.</p>
<p>With my background as a Ground Radio Technician in the USAF, I have general knowledge of radios, antennas, and the basics of UHF/VHF signals. That being said, I know I have a lot to learn when it comes to communicating on HAM radio.</p>
<p>Looking forward to connecting with you!</p>
<p>73 from SD - Levi</p>
</div> </div>
<footer class="entry-footer-container"> <footer class="entry-footer-container">
<div class="entry-footer"> <div class="entry-footer">

+ 6
- 9
views/partials/header.ejs View File

@ -1,16 +1,13 @@
<nav> <nav>
<ul> <ul>
<li class="<% if (active == 'home') { %> logo <% } %>">
<!-- <li class="<% if (active == 'home') { %> logo <% } %>">
<a href="/">home</a> <a href="/">home</a>
</li>
<li class="<% if (active == 'posts') { %> logo <% } %>">
</li> -->
<!-- <li class="<% if (active == 'posts') { %> logo <% } %>">
<a href="/posts">posts</a> <a href="/posts">posts</a>
</li>
<li>
</li> -->
<!-- <li>
<a href="/about">about</a> <a href="/about">about</a>
</li>
<li>
<a href="https://github.com/leothelocust">projects</a>
</li>
</li> -->
</ul> </ul>
</nav> </nav>

Loading…
Cancel
Save