text:
---
title: Who has the fastest website in F1?
date: 2019-03-19 12:00:29
summary: Can I predict the winners of the 2019 F1 season by looking at the
  performance of their websites? No. But I'm gonna anyway.
mindframe: ''
image: ''
meta: ''
---

I was trying to make my predictions for the new Formula One season by studying the aerodynamics of the cars, their cornering speeds, their ability to run with different amounts of fuel. Then it hit me: I have no idea what I'm doing.

So, I'm going to make my predictions the only way I know how: By comparing the performance of their websites. That'll work right?

If anything, it'll be interesting to compare 10 sites that have been recently updated, perhaps even rebuilt, and see what the common issues are. I'll also cover the tools and techniques I use to test web performance.

# Methodology

I'm going to put each site through [WebPageTest](https://www.webpagetest.org) to gather the data on Chrome Canary on a Moto G4 with a 3g connection.

Although a lot of us have 4g-enabled data plans, we frequently [drop to a slower connection](https://www.opensignal.com/reports/2018/02/state-of-lte). A consistent 3g connection will also suggest what the experience would be like in poor connectivity.

Trying to use a site while on poor connectivity is massively frustrating, so anything sites can do to make it less of a problem is a huge win.

In terms of the device, if you look outside the tech bubble, a lot of users can't or don't want to pay for a high-end phone. To get a feel for how a site performs for real users, you have to look at mid-to-lower-end Android devices, which is why I picked the Moto G4.

I'm using Chrome Canary because WPT seems to be glitchy with regular Chrome right now. Yeah, not a great reason, but the test wasn't useful otherwise.

Oh, and whenever I talk about resource sizes, I'm talking about downloaded bytes, which means gzip/brotli/whatever.

## Calculating race time

The amount of bandwidth your site uses matters, especially for users paying for data by the megabyte. However I'm not going to directly score sites based on this. Instead, I'm going to rate them on how long it takes for them to become interactive. By "interactive", I mean meaningful content is displayed in a stable way, and the main thread is free enough to react to a tap/click.

Caching is important, so I'm going to add the first load score to the second load score.

There's some subjectivity there, so I'll try and justify things as I go along.

## Issues with the test

I'm not comparing how 'good' the website is in terms of design, features etc etc. In fact, `about:blank` would win this contest. I love `about:blank`. It taught me everything I know.

I'm only testing Chrome. Sorry. There's only one of me and I get tired. In fact, with 10 sites to get through, it's possible I'll miss something obvious, but I'll post the raw data so feel free to take a look.

I only used "methodology" as a heading to try and sound smart. But really, this is fun, not science.

Also, and perhaps most importantly, the results aren't a reflection of the abilities of the developers. We don't know how many were on each project, we don't know what their deadline was or any other constraints. My goal here is to show how I audit sites, and show the kind of gains that are available.

## Bonus round: images

For each site I'll take a look at their images, and see if any savings can be made there. My aim is to make the image good-enough on mobile, so I'll resize to a maximum of 1000px wide, for display at no larger than 500px on the device's viewport (so it looks good on high density mobile devices).

Mostly, this is an excuse to aggressively push [Squoosh](https://squoosh.app).

Ok. It's lights out, and away we go…

# Mercedes

Mercedes make cars. You might have seen one on a road. They're a big company, so their F1 team is a sub brand. They're also one of the few teams with the same drivers as 2018, so this might not be a 'new' site. Let's take a look:

[Website](https://www.mercedesamgf1.com/en/mercedes-amg-f1/). [WebPageTest results](https://www.webpagetest.org/result/190317_YK_7c6b49c0d79bdfd1f75359c33dcfdb08/).

## First lap

Ok, this is going to be a longer section than usual as I go through the tools and techniques in more detail. Stick with me. The following sections will be shorter because, well, the technique is mostly the same.

I like WebPageTest as it runs on a real devices, and provides screenshots and a waterfall. From the results above, the median first run is 'Run 3', so let's take a look at the 'Filmstrip view':

In terms of user experience, we've got 6.8s of nothing, then a spinner until 13.7s. Showing a spinner is definitely better than showing nothing, but only just. A full-page spinner is basically an admission of being too slow and apologising to the user. But can it be avoided in this case?

WebPageTest's waterfall diagram allows us to match this up with network and main thread activity:

You don't need to use WebPageTest to get this kind of overview. [Chrome DevTools' "Performance" panel](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/) can give you the same data.

Notice how the waterfall has 'steps'. As in, entry 23 is on another step from the things before, and step 50 is on yet another step.

This suggests that something before those things prevented them from downloading earlier. Usually this means the browser didn't know in advance that it needed that resource.

The green vertical line shows 'first render', but we know from the filmstrip that it's just a spinner. Let's dig in.

The green line appears after the first 'step' of items in the waterfall. That suggests one or more of those resources was blocking the render. Viewing the source of the page shows many `<script src>` tags in the head.

```html
<head>
  …
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/en/wp-includes/js/jquery/jquery.js?ver=1.12.4"
  ></script>
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/en/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.4.1"
  ></script>
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/wp-content/plugins/duracelltomi-google-tag-manager/js/gtm4wp-form-move-tracker.js?ver=1.8.1"
  ></script>
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/wp-content/plugins/duracelltomi-google-tag-manager/js/gtm4wp-social-tracker.js?ver=1.8.1"
  ></script>
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/wp-content/plugins/duracelltomi-google-tag-manager/js/analytics-talk-content-tracking.js?ver=1.8.1"
  ></script>
  <script
    type="text/javascript"
    src="https://www.mercedesamgf1.com/wp-content/plugins/events-calendar-pro/src/resources/js/widget-this-week.min.js?ver=4.0.6"
  ></script>
  …
</head>
```

These **block rendering by default**. Adding the `defer` attribute prevents them blocking rendering, but still lets them download early. [Ire Aderinokun wrote an excellent article on this](https://bitsofco.de/async-vs-defer/) if you want to know more.

Adding `defer` to those scripts will allow the page to render before those scripts have executed, but there might be some additional work to ensure it doesn't result in a broken render. Sites that have been render-blocked by JS often come to rely on it.

Ideally pages should render top-to-bottom. Components can be enhanced later, but it shouldn't change the dimensions of the component. I love [this enactment of reading the Hull Daily Mail website](https://www.youtube.com/watch?v=uPnEZd6wCtk), especially how they capture the frustration of layout changes as well as popups. Don't be like that.

For instance, interactive elements like the carousel could display the first item without JS, and JS could add the rest in, plus the interactivity.

  <picture>
    <source type="image/webp" srcset="asset-url:./before-after-js.webp">

  </picture>

This is what I'd like to see. The before-JS render is missing the elements that require JS for interactivity. Once the JavaScript loads, it adds them in.

Looking at the page source, the HTML contains a lot of content, so they're already doing some kind of server render, but the scripts prevent them from taking advantage of it.

[Over on WebPageTest](https://www.webpagetest.org/video/compare.php?tests=190317_YK_7c6b49c0d79bdfd1f75359c33dcfdb08-r:3-c:0) you can click on items in the waterfall for more info. Although at this point I find [Chrome Devtools' "Network" panel](https://developers.google.com/web/tools/chrome-devtools/network/) easier to use, especially for looking at the content of the resources.

The **render-blocking scripts weigh in around 150k**, which includes two versions of jQuery. There's **over 100k of CSS** too. CSS also blocks rendering by default, but you want it to block for initial styles, else the user will see a flicker of the unstyled page before the CSS loads.

[Chrome Devtools' code coverage tool](https://developers.google.com/web/tools/chrome-devtools/network/) says over **80% of the CSS is unused for first render**, along with **75% of the JS.** These should be split up so the page is only loading what it needs. For JavaScript, modern build tools like [webpack](https://webpack.js.org/), [rollup.js](https://rollupjs.org/guide/en), and [Parcel](https://parceljs.org/) support code-splitting for JavaScript.

Splitting CSS isn't as easy. Keeping CSS tightly coupled with their components makes it easier to identify CSS that isn't needed for a particular page. I really like [CSS modules](https://github.com/css-modules/css-modules) as a way to enforce this.

There are tools that automate extracting 'above the fold' CSS. I've had mixed results with these, but they might work for you.

The second 'step' of the waterfall contains some render-altering fonts. The browser doesn't know it needs fonts until it finds some text that needs them. That means the CSS downloads, the page is laid out, _then_ the browser realises it needs some fonts. `<link rel="preload" as="font" href="…">` in the `<head>` would be a quick-win here. This means the browser will download the fonts within the first step of the waterfall. For more info on preloading, check out [Yoav Weiss' article](https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/).

Also, the **fonts weigh in around 350k**, which is pretty heavy. 280k of this is in TTF. TTF is uncompressed, so it should at least be gzipped, or even better use woff2, which would knock around 180k off the size. [`font-display: optional`](https://css-tricks.com/really-dislike-fout-font-display-optional-might-jam/) could be considered here, but given it's part of corporate identity, _sighhhhhhhh_ it might not get past the brand folks.

There's another render-blocking script in this part of the waterfall. The download starts late because it's at the bottom of the HTML, so it should be moved to the `<head>` and given the `defer` attribute.

Then, the Moto 4 gets **locked up for 3 seconds**. You can see this from the red bar at the bottom of the waterfall. WebPageTest shows little pink lines next to script when they're using main-thread time. If you scroll up to row 19, you can see it's responsible for a lot of this jank.

## Second lap

Let's take a look at the second load:

Aside from the HTML, none of the resources have `Cache-Control` headers. But browser heuristics step in, and as a result the cache is used for most assets anyway. This is kinda cheating, and unlikely to reflect reality, but hey, I can't change the rules now. For a refresher on caching, [check out my article on best practices](/2016/caching-best-practices/).

The lack of caching headers seems like an oversight, because a lot of the assets seem to have version numbers. Most of the work has been done, it just lacks a little server configuration.

Unfortunately, despite the heuristic caching, it still takes **5.8s to get into a useable state**, and this is all down to JavaScript execution. The fixes I mentioned above would cover this too. Apply code splitting, and allow rendering before JS.

## Images

They've done a pretty good job of image compression here. They appear to be using some JavaScript to load smaller versions of images for mobile devices. [You don't need JavaScript for this](/2015/anatomy-of-responsive-images/). Using JS for this delays image loading.

Using [Squoosh](https://squoosh.app) I could get the first image down **from 50k to 29k** without significant loss. [See the results](https://f1-images.glitch.me/mercedes.html) and judge for yourself.

## Result

Mercedes 19.5s

So, Mercedes storm into 1st place and last place at the same time, as often happens with the first result.

good HTTPS

good HTTP/2

good Gzip, except TTF

good Minification

good Image compression

bad Render-blocking scripts

bad Late-loading fonts

bad No cache control

bad Unnecessary CSS

bad Unnecessary JS

bad Badly compressed fonts

My gut feeling is the quick-wins (preloading, compressing fonts) would half this time. I imagine the refactoring of the JS and CSS would be a much bigger task, but would bring big results.

# Ferrari

Ferrari also make cars. You might have seen one on a road, driven by a wanker (except my friend Matt who bucks this trend. Hi Matt!).

They have a new driver this year, and a slightly different livery, so this site may have been changed fairly recently.

[Website](https://formula1.ferrari.com/en/). [WebPageTest results](https://www.webpagetest.org/result/190318_5P_f9b7d391cfda6d0228cda70d469e46ba/).

## First lap

In terms of user experience there's **33s of nothing**, some content at 34.3s, but things move around until 36s. This is around twice as long as Mercedes, so things aren't looking good.

Let's dive in:

Wow that's a lot of requests! But, Ferrari use HTTP/2, so it isn't such a big deal. I should mention, this article is a real workout for your scrolling finger.

The stand-out issue is that huge row 16. It's a **render-blocking script**.

It's also on another server, so it **needs to set up a new HTTP connection**, which takes time. You can see this in the waterfall by the thinner green/orange/purple line which signifies the various stages of setting up a connection.

However, the biggest issue with that script, is **it's 1.8mb**. There's also an additional 150k script that isn't minified, and other scripts which sit on different servers.

The **CSS is 66k and 90% unused**, so this could benefit from splitting. There are a few fonts that would benefit from `<link rel="preload">` but they're pretty small. Let's face it, everything is small compared to the JS. Oddly, Chrome's coverage tool claims 90% of the JS is used on page load, which beggars belief.

I dug into their JavaScript and saw a lot of locale data in there, which should be split out, but then I saw a large chunk of base64. You'll never guess what it is. It's this:

No, not the whole thing. The logo. No, not the whole logo, that's SVG. But the horse, the horse is a base64 PNG within the SVG:

Look at it. It's beautiful. **It's 2300x2300.  That logo appears across the main Ferrari site too, so it's probably something the creator of the F1 site had little control over. I wonder if they knew.

Again, there seems to be server rendering going on, but it's rendered useless by the script.

There also seems to be multiple versions of the same image downloading.

## Second lap

The site has ok caching headers, so I'm surprised to see the browser revalidating some of those requests.

The big problem here is still the JS, which takes up two seconds of main thread time. The main-thread then gets **locked up until 10.1s**. This isn't by JavaScript. I'm not 100% sure what it is, but I suspect it's image-decoding that horse.

## Images

First things first, let's tackle that logo. SVG might be the best format for this, but with the bitmap-horse replaced with a much simpler vector-horse (Vector Horse's debut album is OUT NOW). However, I don't have a vector version of the horse, so I'll stick with a bitmap.

The logo is only ever displayed really-tiny in the top-left, at a height of 20px. Using [Squoosh](https://squoosh.app), I'm going to make a 60px version so it stays sharp on high-density devices. **That takes the image from 1.7mb, to a 2.6k PNG, or a 1.7k WebP.** [See the results](https://f1-images.glitch.me/ferrari.html).

One of the initial images on the site is of the 2019 Ferrari. However, it's 1620px wide, and not really optimised for mobile. I took the image down **from 134k to 23k as JPEG, or 16k as WebP** without significant loss. But, [you can be the judge](https://f1-images.glitch.me/ferrari.html#car). WebP shines here because JPEG struggles with smooth gradients – at lower sizes it creates banding which is really noticeable.

The page also contains little track maps that aren't initially displayed. These should be lazy-loaded, but they could also do with a bit of compression. I was able to get one of them down **from 145k to 27k** as a PNG without noticeable loss. Again, [you be the judge](https://f1-images.glitch.me/ferrari.html#track).

## Result

Mercedes 19.5s

Ferrari 46.1s

Last place for now.

Most of their problem is down to one horse. I don't think anyone did that deliberately, but RUM & build time metrics would have made it obvious.

good HTTPS

good HTTP/2

good Gzip

good Caching

bad Render-blocking scripts

bad Unnecessary JS

bad Unnecessary CSS

bad Unminified scripts

bad Unstable render

bad Poor image compression

bad Late-loading fonts

bad Main thread lock-up

bad Horse

# Red Bull

Red Bull aren't a car company. They sell drinks of a flavour I can only describe as "stinky medicine". But, they're also a much more modern, tech-savvy company, so it'll be interesting to see if it shows here.

[Website](https://redbullracing.redbull.com/). [WebPageTest results](https://www.webpagetest.org/result/190315_C3_a4713be271d850097990ca69423bfc4c/).

## First lap

The user experience is 4.9s of nothing, but the result is a broken UI. Things sort themselves out at around 6.5s. There's a font switch at 9.5s, and a horrendous cookie warning at 16s. But, I'd call this visually ready at 6.5s.

Unfortunately we can't call this page ready at 6.5s, as the main thread is **locked up until 11s**. Still, this takes it into 1st place by a couple of seconds.

The story here is very similar to the previous sites. The page contains what looks like a server render, including minified HTML, but **render-blocking scripts** prevent it being shown. The scripts should use `defer`.

**The CSS is 90% unused, and the JS is ~75% unused**, so code-splitting and including only what's needed for this page would have a huge benefit. This might help with the main thread lock-ups too.

Again, the **fonts start loading way too late**. `<link rel="preload">` would be a quick win here.

The icon font times-out, which causes a broken render. There isn't really a good reason to use icon fonts these days. Icon fonts should be replaced with SVG.

The site does use `<link rel="preload">`, but it's mostly used for JS and CSS, which don't really need preloading as they're already in the `<head>`. Worse, they preload a different version of the scripts to the ones they use on the page, so they're **doubling the download**. Chrome's console shows a warning about this.

## Second lap

Thanks to decent caching, we get a render really quickly. However, **JS bogs down the main thread** for many seconds afterwards, so the page isn't really interactive until the 4.8s mark.

Ideally the JavaScript would be chunked up so it only hits the main thead during idle time, or just as the user needs it.

## Images

Like Mercedes, Red Bull uses responsive images, but use JavaScript to make it work. Still, this is better than serving full size images to mobile.

The images could be smaller though. Taking the first image on their page, Using [Squoosh](https://squoosh.app) I can take it down **from 91k to 36k as a JPEG, or 22k as WebP.** [See the results](https://f1-images.glitch.me/redbull.html).

They also use a spritesheet, which might not be necessary thanks to HTTP/2. By bringing the palette down to 256 colours, I can take it down **from 54k to 23k as PNG, or 18k as WebP.** [See the results](https://f1-images.glitch.me/redbull.html#sprites).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Despite issues, Red Bull are straight into 1st place by almost 4 seconds. Nice work!

good HTTPS

good HTTP/2

good Gzip

good Minification, including HTML

good Image compression

good Caching

bad Render-blocking scripts

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

bad Unnecessary icon fonts

# Renault

Back to folks that make cars. Car adverts tend to be awful, but I reckon Renault make the worst ones. Also, [they may have spent too much money on one of their drivers](https://www.youtube.com/watch?v=r7wSxA1P4XM) and not have enough left over for their website. Let's see…

[Website](https://www.renaultsport.com/-Formule-1-330-.html). [WebPageTest results](https://www.webpagetest.org/result/190315_5N_e5c1d85d3f7dd0701b96359352761388/).

## First lap

The user gets 5.8s of nothing, then a broken render until 7.8s, but the **intended content of the page doesn't arrive until 26.5s.** Also, asking for notification permission on load should be a black flag situation, but I'll be kind and ignore it.

As with previous sites, **render-blocking scripts** account for the first 5.8s of nothing. These should use `defer`. However, this script doesn't get the page into an interactive state, it delivers a broken render.

Then, something interesting happens. The scripts that are needed to set up the page are at the bottom of the HTML, so the browser gives these **important scripts a low priority**.

You can see from the waterfall that the browser starts the download kinda late, but not that late. The darker area of the bars indicates the resource is actively downloading, but in this case the scripts are left waiting until other things such as images download. To fix this, these important scripts should be in the `<head>` and use the `defer` attribute. The page should be fixed so the before-JS render is usable.

**The CSS is 85% unused, and the JS is ~55% unused**, so it would benefit from splitting.

As with the other pages the **fonts load late**. It's especially bad here as images steal all the bandwidth (more on that in a second). Preloading fonts is a huge & quick win, and icon fonts should be replaced with SVG.

## Second lap

The caching is pretty good here, but a few **uncached scripts** push the complete render back to 5.9s. The first lap fixes would help here, along with some `Cache-Control` headers.

## Images

Images play quite a big part in the performance here.

I took their first carousel image and put it through [Squoosh](https://squoosh.app). This took the size from **314k down to 59k as a JPEG, or 31k as WebP.** I don't think the compression is too noticeable, especially as text will be rendered over the top. [Judge for yourself](https://f1-images.glitch.me/renault.html).

Their driver pictures are PNGs, which is a bad choice for photo data. I can get one of them **from 1mb down to 21k** as a JPEG. [See the results](https://f1-images.glitch.me/renault.html#driver).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

The download priority of those important scripts hits hard here, and the images still all the bandwidth. These things can be easily fixed, but are slowing the site down by 15+ seconds.

good HTTPS

good HTTP/2

good Gzip

good Minification

good Caching

bad Image compression

bad Render-blocking scripts

bad Unstable render

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

bad Unnecessary icon fonts

# Haas

Haas are the newest team in F1 (unless you count rebrands), so their website should be pretty new. They've kept their drivers from last year, despite [one of them](https://www.youtube.com/watch?v=SoLrLqqAGbI) managing to crash at slow speeds for no reason, and blame another driver who wasn't there.

Their car looks pretty different this year with the arrival of a new sponsor, Rich Energy. Y'know, Rich Energy. The drink. You must have heard of it. Rich Energy. It's definitely not some sort of scam.

[Website](https://www.haasf1team.com/). [WebPageTest results](https://www.webpagetest.org/result/190315_P4_156ead72882bf25ec72bfb152d174fc0/).

## First lap

The user gets **4.5s of nothing**, and then it's interactive! Pretty good!

It takes a long time for that first image to show, but hey, it doesn't block interactivity.

It terms of improvements, it's a similar story. There's a server render, but it's blocked by **render-blocking scripts** in the `<head>`.

These come from a couple of different servers, so they pay the price of **additional HTTP connections**. But, the amount of script blocking render is much smaller than other sites we've looked at so far.

Only **a fraction of the JS and CSS is used**, so splitting those up would really improve things. The main **CSS isn't minified** which hurts load time slightly.

Again, **font preloading would help** here.

## Second lap

A good caching setup reduces the amount of network traffic. However a combination of image decoding, JavaScript, and layout hits hard, **locking up the main thread** until the 8 second mark.

Their second load is slower than their first. Because their overall load time for the first load is network-limited, things like image decoding and script execution happen gradually. In this case, it all lands at once.

## Images

Things aren't great here.  I guess they were uploaded via a CMS which doesn't recompress the images for the web.

Using [Squoosh](https://squoosh.app) (have I mentioned Squoosh yet?), I can take those thumbnails **from 3mb to around 56k as a JPEG, and 44k as WebP**. [See the results](https://f1-images.glitch.me/haas.html).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

Despite problems, they jump into 1st place! However, it feels like it could be a lot faster by solving some of the main-thread issues.

good HTTPS

good HTTP/2

good Gzip

good Minification (mostly)

good Caching

bad Image compression

bad Render-blocking scripts

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

# McLaren

McLaren do sell the occasional car, but they're a racing team through and through. Although, in recent years, they've been a pretty slow racing team, and as a result they've lost their star driver. But will the website reflect the problems they're having on track?

[Website](https://www.mclaren.com/formula1/). [WebPageTest results](https://www.webpagetest.org/result/190316_1P_abeb79b44af2270a27d774f3a5da939d/).

## First lap

In terms of user experience, the user gets nothing for the first 10.6 seconds, but the **content jumps around until 24.3 seconds**.

The first problem we see in the waterfall is the amount of **additional connections needed**. Their content is spread across many servers.

Their **main CSS is 81k, but 90% unused** for the initial render. Ideally the stuff needed for first render would be inlined, and the rest lazy-loaded.

Then there's a request for some fonts CSS (row 6). It's on yet another server, so we get another connection, and it **serves a redirect** to yet another server (row 10).

The CSS it eventually serves is **137k and uncompressed**, and is mostly base64 encoded font data.

This is the biggest thing blocking first render. It's bad enough when text rendering is blocked on font loading, but in this case the whole page is blocked. Ideally, required fonts should be served as their own cachable resources, and preloaded.

Then we get their JS bundle, which is **67% unused**, so could benefit from some code splitting. It's also located at the bottom of the HTML, so it'd benefit from being in the `<head>` with `defer`. This would make it start downloading much sooner.

Then we get a request for 'jsrender', which seems to be the framework this site uses. This sits on yet another server, so they pay the price of yet another connection.

The content that appears at 24s is included as JSON within the HTML, and it isn't clear why it takes so long to render. Their main script uses a lot of main thread time, so maybe it's just taking ages to process all the template data, and isn't giving priority to the stuff that needs to appear at the top of the page.

This is the first site so far that serves its content in JavaScript rather than HTML.

## Second lap

Caching headers are mostly absent, but browser heuristics make it look better than it is. The number of connections needed still hits hard, as does the JS processing time.

The content **doesn't appear until 16.4s**, and it's worth noting that the main thread is still really busy at this point.

## Images

They have a 286k spritesheet which needs breaking up, and perhaps replaced with SVG. Usually I would try to reduce the palette on something like this, but it loses too much detail. Anyway, I can get it down **from 286k to 238k as a PNG, and 145k as WebP** without any loss at all. [See the results](https://f1-images.glitch.me/mclaren.html).

They avoid downloading large images until the user scrolls, which is nice. Taking one of the images that arrives, I can get it **down from 373k to 59k as a JPEG and 48k as WebP.** [See the results](https://f1-images.glitch.me/mclaren.html#photo).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

McLaren 40.7s

Not back-of-the-grid, but close. To be competitive, this site needs proper caching, fewer connections, and a decent before-JavaScript render.

good HTTPS

good HTTP/2

good Gzip

good Minification

good Lazy-loading images

bad Render-blocking scripts

bad Unstable render

bad No cache control

bad Image compression

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

bad Too many HTTP connections

# Racing Point

Lance Stroll wanted to be a racing driver, so daddy bought him an entire F1 team. That team is called Racing Point because I dunno maybe they were trying to pick the dullest name possible.

[Website](https://www.racingpoint.com/). [WebPageTest results](https://www.webpagetest.org/result/190316_XS_121a1e8cd67fe1f62fe0e1e45883fe03/).

## First lap

The user gets nothing for 45s, but the intended top-of-page content **isn't ready until the 70s mark**.

Also, the main thread is **too busy for interaction until 76s**.

The page starts by downloading **300k of CSS that's served without minification, and without gzip**. Minifying and gzipping would be a quick win here, but with **over 90% of the CSS unused**, it'd be better to split it up and serve just what this page needs.

Also, this CSS imports more CSS, from Google Fonts, so it pays the cost of **another connection**. But the main problem is the browser doesn't know it needs the fonts CSS until the main CSS downloads, and by that time there's a lot of stuff **fighting for bandwidth**.

`<link rel="preload">` would be a huge and quick win here, to get that CSS downloading much earlier. It's the CSS that's currently blocking first render.

The site also suffers from **late-loading scripts**.

These scripts are at the bottom of the `<body>`, so they don't block rendering. However, if this JS is going to pop-in content at the top of the page, that space should be reserved so it doesn't move content around. Ideally a server-render of the carousel's first frame should be provided, which the JS can enhance. Also, these scripts should be in the `<head>` with `defer` so they start downloading earlier. Like the CSS, they **lack minification and gzipping**, which are quick wins. The **JS is also 64% unused**, so could be split up.

The carousel JS waits until the images (or at least the first image) has downloaded before displaying the carousel. Unfortunately the **first image is 3mb**. There's also a **6mb image** on the page, but that isn't blocking that initial content render. These images need compressed (more on that in a second). The carousel should also avoid waiting on the images, and maybe provide a low resolution version while the full image downloads.

The main thread is then locked up for a bit. I haven't dug into why, but I suspect it's image decoding.

## Second lap

The site has **pretty good caching headers**, so very little is redownloaded second time around. However, we don't get the main content until 8.2s due to **main thread contention**. This is a mixture of JavaScript, but mostly (I suspect) image decoding.

## Images

For this one, image performance really matters in terms of first render. I got that **3mb image down to 57k as a JPEG, and 39k as WebP.**  [You be the judge](https://f1-images.glitch.me/racing-point.html).

Also, their logo is **117k.** I'm sure the brand folks would like it to load a bit quicker. By resizing it and reducing colours to 100, I got it **to 13k as a PNG, and 12k as WebP.** [See the results](https://f1-images.glitch.me/racing-point.html#logo). An SVG might be even smaller.

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

McLaren 40.7s

Racing Point 84.2s

You might have to scroll a bit to see this one.

The problem here is compression and timing. With image, CSS, JS compression, and some CSS preloading, this score would be < 20s. With a good server render of the carousel, it could be < 10s. Unfortunately it's back-of-the-grid for Racing Point.

good HTTPS

good HTTP/2

good Caching

good No render-blocking scripts

bad No gzip

bad No minification

bad Image compression

bad Unstable layout

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

bad Late-loading CSS

bad Late-loading JS

# Alfa Romeo

Alfa Romeo make cars, but they don't really make the one they race. The engine is a Ferrari, and the aero is the work of Sauber, which was the name of this team before 2019. But, a new brand often come with a new website. Let's see how it performs…

[Website](https://www.sauber-group.com/motorsport/formula-1/). [WebPageTest results](https://www.webpagetest.org/result/190316_J4_faa55eb9e863ce8c80b1f4f4709501c3/).

## First lap

The user gets nothing for 7.9s, but they only get **a spinner until 15.6s**. You have to scroll to get content, but I'll count this as interactive.

The render is **blocked until the Google Fonts CSS downloads**, which points to a similar problem as Racing Point.

And yep, their main CSS (row 2) imports the Google Fonts CSS (row 9). This should be preloaded to allow the two to download in parallel. It's especially bad here, as the font they're downloading is Roboto, which already exists on Android, so no fonts are actually needed.

The main CSS is pretty small, but still **85% unused**, so splitting and perhaps inlining would help a lot here.

After parsing the HTML, the browser discovers a load of images it needs to download, then a couple of scripts at the bottom of the page.

However, these scripts are essential to the rendering of the page, so they're **loading far too late**. A quick win would be to move them to the `<head>` (they already have `defer`). This would save around 8 seconds.

The **JS is also 85% unused**, so splitting would definitely help.

This page shouldn't need a spinner. Instead, it could have a before-JS render. The page is mostly static, so there aren't too many challenges here.

## Second lap

The site makes **excellent use of caching**, but the JS-driven rendering slows things down. The **main thread is jammed** for a few seconds thanks to a combination of JavaScript and image decoding, getting to render in 4.5s.

The things which would make the first lap faster would also help here.

## Images

The image right at the top of the page is **236k**. Using [Squoosh](https://squoosh.app), I managed to get this **down to 16k as a JPEG, and 9k as a PNG.** [See the results](https://f1-images.glitch.me/alfa-romeo.html).

The page also loads a lot of logos. None of them are particularly big themselves, but they add up. I took one example **from 18k down to 7k as a PNG.** [See the results](https://f1-images.glitch.me/alfa-romeo.html#logo). This kind of saving across all the logos would be significant.

 They fund two 'independent' teams in F1, with this one being a kinda "B team". But, can they beat their sister team on the web?

[Website](https://scuderiatororosso.redbull.com/en/). [WebPageTest results](https://www.webpagetest.org/result/190319_0P_d78344080cf958e96a1af334ef5cc40a/).

## First lap

In terms of user experience, the user gets 4.7s of nothing. But, text doesn't start to appear until 5.4s. Then, more text appears gradually, and **seems complete at 5.8s**. Not bad!

Unfortunately the main thread is **blocked until 8s**. This looks like image decoding, but I'm not sure.

Very much like the other sites we've seen, they serve HTML but it's blocked by **render-blocking scripts**. They should use `defer`.

The **CSS is 90% unused**, and the **JS is over 50% unused**. Splitting would help here. There are also late-loading scripts that would benefit from being in the `<head>` with `defer`. There's also some **unminified scripts** thrown in there too. But, despite this, their JS & CSS isn't too big.

The biggest performance problem this site has is fonts. That's why the text comes in late.

The **fonts are late-loading**, so preloading them would have a huge benefit here.

The fonts are also a little big. Using **woff2 would be a quick win** here, but it might be worth considering getting rid of some of the fonts all together. But yeahhhhh that can be a tough argument to have.

## Second lap

We get content at 5s, but the **main thread is locked until 7s.** Again, I think this is down to images.

The caching headers are mostly great, except for the **fonts which only cache for 30 seconds.** That's why we see so many revalidations in the waterfall above. Allowing the fonts to cache for longer would have saved a good few seconds here.

## Images

You'll never guess what. I decided to use [Squoosh](https://squoosh.app) here. Their top image isn't really optimised for mobile. I managed to get it **down from 152k to 26k** as a JPEG. [See the results](https://f1-images.glitch.me/toro-rosso.html).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

McLaren 40.7s

Racing Point 84.2s

Alfa Romeo 20.1s

Toro Rosso 12.8s

So close! Only a couple of tenths off Haas. With font preloading and some image compression, they'd easily be in 1st place.

good HTTPS

good HTTP/2

good Gzip

good Minification (mostly)

good Caching (mostly)

bad Image compression

bad Render-blocking scripts

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

bad Late-loading fonts

# Williams

Williams are probably my favouite team. They're relatively small, independent, and have an incredible history. However, their last few seasons have been awful. Hopefully that won't reflect on their website…

[Website](https://www.williamsf1.com/). [WebPageTest results](https://www.webpagetest.org/result/190316_DQ_f6d91d400454e78f6e00249e4dd5594e/).

## First lap

In terms of user experience, the user sees **nothing until 7.9s**, but then they have visible content.

The first thing that stands out here is all the additional connections.

I thought this meant they were using a lot of different servers, but a closer look shows they're **using old HTTP/1**. This means the browser has to set up separate connections for concurrent downloads. A switch to HTTP/2 would be a big win.

But look, those fonts are arriving nice and early. A quick look at their source shows they're using `<link rel="preload">`, yay!

 Splitting and inlining these would show a big improvement.

Then we get a few **render-blocking scripts** in the head. These should be `defer`d to allow the server render to show before JS loads. The page is pretty much static so this shouldn't be too hard.

Their main JS loads at the end of the document, and it's a **whopping 430k**. This page barely needs any JS at all, so I'm pretty sure that can be significantly reduced, if not discarded. Thankfully it doesn't block render.

## Second lap

The **caching headers are good**, so very few requests are made on the second run. However, HTTP/1 slows down the initial request, then that massive script arrives from the cache and takes up **1.5s of main thread time**. In total, it takes 6.2s to render.

The fixes from the first run will also fix these issues.

## Images

I took a look at the main image. It's a wide image, but the sides aren't shown on mobile. Also, it has a dark overlay over the top, which reduces the fidelity of the image. I cropped the image a bit, and applied the overlaid colour to the image, so the compressor could optimise for it. Using [Squoosh](https://squoosh.app) (drink!), I got the size **from 267k to 48k as a JPEG, and 34k as WebP.** Since text is rendered over the top, it might be reasonable to compress it more. [See the results](https://f1-images.glitch.me/williams.html).

## Result

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

McLaren 40.7s

Racing Point 84.2s

Alfa Romeo 20.1s

Toro Rosso 12.8s

Williams 14.1s

Despite issues, this is one of the fastest times. With HTTP/2, it might have jumped into 1st place.

good HTTPS

good Gzip

good Minification

good Caching

good Preloading fonts

bad HTTP/1

bad Render-blocking scripts

bad Image compression

bad Main thread lock-up

bad Unnecessary CSS

bad Unnecessary JS

# Fantasy F1

I'm going to throw the official fantasy F1 site into the mix too. It's my blog I can do whatever I want.

[Website](https://fantasy.formula1.com/). [WebPageTest results](https://www.webpagetest.org/result/190317_HB_adaeac4882b9e2e1201f28ff627a849f/).

## First lap

In terms of user experience, the user gets nothing until 12s. But the text for the main call-to-action doesn't display until **14.5s**.

The **main thread looks blocked** until at least the 15s mark.

This is the first site we've seen with a near-empty `<body>`, and also the first to use one of the modern frameworks (Ember).

Initial render is blocked on CSS and **render-blocking scripts**.

Because the render is JavaScript driven, the browser doesn't know much about the resources it needs to download until Ember renders the page. That's why we see a load of requests begin around the 9.5s mark:

The page would benefit massively from a server render. But, given there isn't really any interactivity on this page, they could consider removing the JS all together, or preloading it for when it is needed. It certainly doesn't need 700k of JS. [Netflix removed React from their landing page](/2017/netflix-and-react/) and saw a huge speed boost. The same could be done here.

The **CSS is 95% unused**, so it could be split up so this page can use the necessary parts.

The button text appears late because of **late-loading fonts**. Which is also excasserbated by the JavaScript-render.

As with other pages, this page would benefit hugely from font preloading. Also some of the fonts are TTFs. They're gzipped, but **woff2 would be much smaller**.

## Second lap

The JS URLs look versioned, but their `Cache-Control` header requires the browser to check for an update every time. You can see that in the 304 responses in the waterfall.

Once the scripts have landed, they **lock up the main thread** until at least the 7s mark. Again, removing JavaScript and making this a mostly static page would improve things massively.

## Images

In terms of images, I took a look at the main background image at the top of the page. The team have clearly tried to make this small, because the JPEG compression is pretty visible. However, it has the same problem as the Williams image – most of it isn't visible on mobile, and it has an overlay.

I baked the overlay into the image, cropped it a bit, and took it down **from 170k down to 54k as a JPEG, and 43k as WebP.** It might be possible to go lower, but I was already dealing with an image with a lot of compression artefacts. [See the result](https://f1-images.glitch.me/fantasy.html).

There's also a 219k PNG. I think it's a PNG because it has transparency, but it's only ever displayed over a white background. I gave it a solid background, and took it **down to 38k as a JPEG, and 20k as WebP.** [See the result](https://f1-images.glitch.me/fantasy.html#diagram).

Another image caught my eye. There's an image of the Spanish flag as an SVG (29k), which can be optimised via [SVGOMG](https://jakearchibald.github.io/svgomg/) to 15k. However, the Spanish flag is pretty intricate, and displayed really tiny on the site (30x22). I got it **down to 1.2k as a PNG, and 800b as WebP.** [See the result](https://f1-images.glitch.me/fantasy.html#flag).

Although SVG is usually the best choice for logos, sometimes a PNG/WebP is better.

 How do the all compare?

# Final results

Ok here we go!

Mercedes 19.5s

Ferrari 46.1s

Red Bull 15.8s

Renault 32.4s

Haas 12.5s

McLaren 40.7s

Racing Point 84.2s

Alfa Romeo 20.1s

Toro Rosso 12.8s

Williams 14.1s

Fantasy F1 22.0s

Congratulations to the Haas team who cross the finishing line first, and have the fastest website in Formula One. Toro Rosso are really close, and Williams complete the podium.

# Final thoughts

This has been kinda eye-opening for me. In my job, I feel I spend a lot of time trying to convince users of frameworks to get a meaningful static/server render as part of their build process early on. It has a huge impact on performance, it gives you the option of dropping the client-side part of the framework for particular pages, and it's incredibly hard to add later. However, none of the teams used any of the big modern frameworks. They're mostly Wordpress & Drupal, with a lot of jQuery. It makes me feel like I've been in a bubble in terms of the technologies that make up the bulk of the web.

It's great to see HTTPS, HTTP/2, gzip, minification, and decent caching widely used. These are things folks in the performance community have been pushing for a long time, and it seems like it's paid off.

However, one of the bits of performance advice we've been pushing the longest is "don't use render-blocking scripts", yet every site has them. Most of the sites have some sort of server/static render, but the browser can't display it due to these blocking scripts.

Pretty much every site would massively benefit from font preloading. Although I'm not suprised it's missing from most sites, as preloading hasn't been in browsers as long as other performance primitives. I guess code splitting is newish too, which is why there isn't a lot of it.

It feels like the quick-wins would cut the times down by 25%, if not more. An unblocked render would bring many down to the 5 second mark.

Some of the issues feel like they may have happened after the site was launched. Eg, a too-big image was uploaded, or a massive horse was added to the header. RUM metrics and build reporting would have helped here – developers would have seen performance crashing as the result of a particular change.

They aren't totally comparable, but this page (which is kinda huge and has a lot of images) would score 4.6s on the same test ([results](https://www.webpagetest.org/result/190319_3D_9a8b75faf6747b38417ca081d171baa6/)). [Squoosh](https://squoosh.app) would score 4.2s ([results](https://www.webpagetest.org/result/190316_PA_cec874a40f1428ab7a8ae020a41b6e54/)), but we spent a lot of time on performance there. Most of this is down to an unblocked initial render and code splitting.

Anyway, does this mean Haas are going to win the 2019 Formula One season? Probably. I mean, it makes sense right?

gha_language: TypeScript


text:
# [Startup Quotes](http://alexa.amazon.com/#skills/amzn1.ask.skill.bcf71cbd-3f68-4150-b358-94052db7919b)
![5 stars](../../images/ic_star_black_18dp_1x.png)![5 stars](../../images/ic_star_black_18dp_1x.png)![5 stars](../../images/ic_star_black_18dp_1x.png)![5 stars](../../images/ic_star_black_18dp_1x.png)![5 stars](../../images/ic_star_black_18dp_1x.png) 2

To use the Startup Quotes skill, try saying...

* *Alexa Open Startup Quotes*

* *Alexa Ask Startup Quotes For Some Motivation*

* *Alexa Ask Startup Quotes For A Quote*

With a collection of startup and motivation quotes "Startup Quotes" will keep your going when you need a bit of wisdom from those who came before us because we all need hustle,  inspiration, and motivation, get yours here.

***

### Skill Details

* **Invocation Name:** startup quotes
* **Category:** null
* **ID:** amzn1.ask.skill.bcf71cbd-3f68-4150-b358-94052db7919b
* **ASIN:** B01MTLNLMZ
* **Author:** Abe Diaz
* **Release Date:** December 15, 2016 @ 06:49:40
* **In-App Purchasing:** No

license: MIT

branch_name: refs/heads/master

extension: md

license_type: permissive


text:
Title: Introduction to your project
Summary: Help page for the impatient

## Markdown

Here you can describe your project, using a simple Markdown file, and put
[links][link] and other cool markdown stuff.

Your booklet source files (markdown documents) should be in the `src` directory.

This is a Github-flavored markdown parser, so you can add:

> Quotes to enhance your text.

or maybe code, if you like:

```python
print('hello world')
```

---

Tables are very very handy:

| Stuff      | Result                                  |
|:---------- |----------------------------------------:|
| Row 1      | These boots                             |
| Row 2      | are made                                |
| Other rows | for walking, and that all what they do  |

## Markdown extensions

This boilerplate project comes with handy extensions:

### Fragments

Put fragments that could be used more than once in your booklet, and "include"
them in several documents.

Step 1: put a file in your ``src/fragments`` directory. For example,
``fragment-test.md``. Edit its content, using the same Markdown syntax.

Step 2: add this line in a document:

```
~~fragment-test.md~~
```

This will add the fragment to the target document.

### Admonitions

Available pre-built ReST-like admonitions:

* note
* rule
* info
* warning
* handwritten

```
    !!! note

        This is a note and this will be transformed into a "div.note" HTML tag
        container.
```

will be generated as:

!!! note

    This is a note and this will be transformed into a "div.note" HTML tag
    container.

If you want, you may add a custom title to your admonition:

```
    !!! info "Helpful reminder"

        You are reminded that you can add titles.
```

!!! info "Helpful reminder"

    You are reminded that you can add titles.

You can add as many admonition as you want, you'll only have to define the CSS
look and feel in the `style.css` file. The sky is the limit.

#### Samples

!!! warning

    This is a warning

!!! handwritten "example"

    Handwritten text is so pretty.

## Navigation

another useful tool is the navigation toolkit. Edit the `navigation.json` file
to fit your architecture. It's a basic list that will generate a nav tree. There
are two types of "rows": captions and navigation items.

```
    {"caption": "First section"}
```

This will be rendered as a simple link-less tree item, pretty much like a
separator.

```
    {"url": "quickstart", "caption": "Quickstart"}
```

This will produce a link to the content of the `quickstart.md` file. The target
URL will be `/quickstart/`.

[link]: https://github.com/

repository: brunobord/booklet-boilerplate

repo_name: brunobord/booklet-boilerplate


text:
# Service Binding Operator Acceptance Tests

## Pre-requisities

### OpenShift Client (`oc`) v4.5+

Get the `oc` binary from [here](https://mirror.openshift.com/pub/openshift-v4/clients/ocp/), ideally the matching version to your OpenShift or CRC version.

### OpenShift or CRC v4.5+

If you have an OpenShift 4.5+ cluster available, you can use it or get the CodeReady Containers binaries with an embedded OpenShift disk image from [this page](https://cloud.redhat.com/openshift/install/crc/installer-provisioned) and install the `crc` into your system.

Let the version of CRC is `4.6.15`.

Setup CRC:
```bash
crc setup

.
.
.
Setup is complete, you can now run 'crc start' to start the OpenShift cluster
```

Start local CRC instance:
```bash
crc start

.
.
INFO Creating CodeReady Containers VM for OpenShift 4.6.15...
.
.
INFO Starting OpenShift cluster ... [waiting 3m]
.
.
INFO To access the cluster, first set up your environment by following 'crc oc-env' instructions
INFO Then you can access it by running 'oc login -u developer -p developer https://api.crc.testing:6443'
INFO To login as an admin, run 'oc login -u kubeadmin -p ****-*****-*****-***** https://api.crc.testing:6443'
INFO
INFO You can now run 'crc console' and use these credentials to access the OpenShift web console
```

You can also figure out those credentials by running:
```bash
crc console --credentials

To login as a regular user, run 'oc login -u developer -p developer https://api.crc.testing:6443'.
To login as an admin, run 'oc login -u kubeadmin -p ****-*****-*****-***** https://api.crc.testing:6443'

```

## Set environment
`KUBECONFIG` env variable needs to be set for the `oc` to be able to communicate with the cluster

### OpenShift

```bash
export KUBECONFIG=<path-to-kubeconfig>
```

### CRC
```bash
export KUBECONFIG=$HOME/.crc/cache/crc_libvirt_4.6.15/kubeconfig
```

### Verify `oc` is working with your cluster
```bash
oc status

In project default on server https://api.crc.testing:6443
...
```

## Run acceptance tests

Let's use `WORKSPACE` as a placeholder for the path of your local Service Binding Operator repository.

```bash
export WORKSPACE=<path-to-sbo-repo>
cd $WORKSPACE
```

Every output artifact (such as SBO's logs or test reports) related to the acceptance tests can be found under `$WORKSPACE/out/acceptance-tests` directory during and after the test execution.

The acceptance test scenarios are defined in a [Gherkin Syntax](https://cucumber.io/docs/gherkin/), that is `Given -> When -> Then` while the individual steps are in a English-like, human readable, language (e.g. [bindAppToService.feature](https://github.com/redhat-developer/service-binding-operator/blob/master/test/acceptance/features/bindAppToService.feature)).

There are couple of `Makefile` targets that runs acceptance tests:

* `test-acceptance-smoke` - Execute `smoke` sub-set of acceptance tests
* `test-acceptance` - Execute all the acceptance tests

Let's take a look each of them.

### Run all acceptance tests with local instance of SBO

```bash
make test-acceptance
.
.
.
```

This command will prepare the environment so that:
* Deletes the old namespace from any previous run,
* Creates a new namespace with generated name like `test-namespace-xxxxxxxx`,
* Installs all the dependencies such as CRD, role, role-binding, service-account, etc. all for the service binding operator to be able to run,

and:
* Builds and start a local instance of the operator,
* Finally, executes the acceptance tests [features and scenarios](https://github.com/redhat-developer/service-binding-operator/tree/master/test/acceptance/features).

At the end of the acceptance tests execution there's a summary printed out:

```bash
.
.
.

4 features passed, 0 failed, 0 skipped
13 scenarios passed, 0 failed, 4 skipped
149 steps passed, 0 failed, 40 skipped, 0 undefined
Took 24m13.854s
```

### Run acceptance smoke tests with local instance of SBO

There is possibility to run a smaller sub-set of selected acceptance test scenarios as smoke test.

To run acceptance smoke tests with local instance of SBO:

```bash
make test-acceptance-smoke
.
.
.
```

This command will prepare the environment similarly to the previous one and:
* Builds and start a local instance of the operator
* Executes the `smoke` sub-set of acceptance tests [features and scenarios](https://github.com/redhat-developer/service-binding-operator/tree/master/test/acceptance/features) - marked with `@smoke` tag.

### Run acceptance tests with remote instance of SBO

It is possible to run the acceptance tests with SBO already running, that is without building and starting the local instance and without installing the dependent resources (such as CRD, role, role-binding, service-account, etc.) required when the local instance is used. That is particularly useful for testing SBO installed on a remote cluster or running the acceptance tests with various versions of the SBO.

For that there is `TEST_ACCEPTANCE_START_SBO` environment variable that needs to be set to `remote`.

The remote cluster where the SBO should be running is determined by the `KUBECONFIG`.

To run acceptance tests with remote instance of SBO:

```bash
TEST_ACCEPTANCE_START_SBO=remote make test-acceptance
```

Compared with the defaults this command only:
* Deletes the old namespace from any previous run,
* Creates a new namespace with generated name like `test-namespace-xxxxxxxx`,
* Executes the acceptance tests.

### Run acceptance tests with SBO installed from a given index image

This is similar to the running the acceptance tests with a remote instance of the SBO, however in this case the SBO is being installed from a given index image before the acceptance tests are executed.

For that there is `OPERATOR_INDEX_IMAGE_REF` environment variable that can be used to specify the given index image.

The remote cluster where the SBO should be installed is determined by the `KUBECONFIG`.

To run acceptance tests with the remote instance of SBO installed from [OperatorHub.io](https://operatorhub.io/operator/service-binding-operator)'s index image:

```bash
OPERATOR_INDEX_IMAGE_REF=quay.io/operatorhubio/catalog:latest make test-acceptance-with-bundle
```

To run acceptance tests with the remote instance of SBO installed from the latest master's index image (`OPERATOR_INDEX_IMAGE_REF` variable is set to `quay.io/redhat-developer/servicebinding-operator:index` by default):

```bash
make test-acceptance-with-bundle
```

### Run a sub-set of features or scenarios

It is possible to run a sub-set of features or even a single scenario (for example, when you are working on a new scenario and you need to run it over and over). The way how to do it is by "marking" that feature or scenario by a "tag" - directly in the particular `*.feature` file - in a form of `@<tag>` (e.g. `@wip`). Something like the following:

```gherkin
Feature: ...

   @wip
   Scenario: Bind service 1 to app 1
   ...

   Scenario: Bind service 1 to app 2
   ...
```

Now, when you want to execute just that scenario out of the whole suite, use the `TEST_ACCEPTANCE_TAGS` environmental variable to set the tag.

To run single scenario tagged with `@wip`:

```bash
TEST_ACCEPTANCE_TAGS=@wip make test-acceptance
.
.
.

```

Only the scenario or feature tagged with the particular tag (`@wip` in case of our example) will be executed, and all of the others will be simply skipped.

```bash
.
.
.

1 feature passed, 0 failed, 3 skipped
1 scenario passed, 0 failed, 16 skipped
10 steps passed, 0 failed, 179 skipped, 0 undefined
Took 0m49.231s
```

## Inspect test results

During the test execution the result of individual steps are shown as the execution goes. That is the most obvious way to see the results, but it is far from elegant - especially with a growing number of scenarios. However, the framework also records the test results in a standardized way of xUnit format, which can be found under `$WORKSPACE/out/acceptance-tests` directory.

As mentioned above those `*.xml` test results files are in xUnit format, which is standardized although it is not human readable. To make it readable a tool for visualizating is needed to help us.

There's one tool in particular that is meant for BDD-like results and that is [Allure](https://docs.qameta.io/allure/)

The following actions use this tool to visualize the results in a form of interactive HTML reports.

### Serve interactive HTML test result report

```bash
make test-acceptance-serve-report
```

This command generates an HTML report and runs a local HTTP server in a container called `test-acceptance-report`. This report can be access at `http://localhost:8088`.

### Generate interactive HTML test results report

```bash
make test-acceptance-generate-report
```

This command uses the `out/acceptance-tests/*.xml` xUnit results and generates a HTML report into `out/acceptance-tests-report` directory that can be served by any HTTP server.

:warning: However, openning the report in Chrome is blocked by a security feature of the Chrome browser that prevents cross-origin requests to the local file system. That results in an error similar to the following:

```txt
Failed to load file:///...: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
```

So locally is better to use the above `test-acceptance-serve-report`.

That's all Folks! ...well, at least for now.

gha_language: Go


text:
Pattern: Use of precision alignment

Issue: -

## Description

Warns on line indentation ending with spaces for precision alignment.

WP demands tabs for indentation. In rare cases, spaces for precision alignment can be
intentional and acceptable, but more often than not, this is a typo.

## Further Reading

* [WordPress PHP Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#indentation)

repository: Adroiti/docs-for-code-review-tools

repo_name: Adroiti/docs-for-code-review-tools


text:
---
title: Conserving Energy
date: December 4 2006
slug: conserving-energy
---

Posted on Dec 04, 2006

Conserving energy has a big payoff

  The university has received a $66,000 incentive award from PG&E for
  conserving the natural gas and electricity used to heat and light campus
  buildings.

  The award is one of several the university has received from the utility over
  the past two years for excellence in energy planning and conservation.

  Studying how a building's environmental systems -- heating, ventilating
  and lighting -- perform and modifying or adjusting each system to gain the
  most efficiency is how the university achieved the savings that resulted in
  the award. Nine campus buildings were analyzed for this latest project.

  The program under which PG&E awarded the money is known as the Energy
  Efficiency Partnership. It was established as a team effort among the
  California State University system, the University of California system and
  utility companies, including PG&E, Southern California Edison and San
  Diego Gas & Electric. The Public Utilities Commission uses fees it
  collects on utility bills to provide a financial incentive to the CSU and UC
  campuses to improve energy efficiency.

  PG&E pays up to 80 percent of the cost of a previously approved
  energy-saving project, with the campus paying the rest.

  "For 2006 to 2008, $14.8 million is earmarked for the 23 CSU campuses for
  this program to evaluate energy-saving opportunities, get them approved and
  implement conservation plans," said Mike Lerch, CSUMB's energy
  manager. "Typically, we can save 5 to 8 percent of what the university
  pays for electricity and gas."

  This is the third award from PG&E the university has garnered. In 2005,
  five buildings were monitored for efficiency and changes made to their
  systems, earning CSUMB a $152,000 incentive payment.

  This year, another $42,000 is pending for replacing inefficient lighting on
  campus. The lighting in the university's gym has already been completed.

<fieldset class="fieldgroup group-attachments">
  <legend>Attachments</legend>

</fieldset>

repository: csumb-archives/news-gatsby

gha_language: JavaScript

gha_license_id: MIT

repo_name: csumb-archives/news-gatsby


text:
---
title: Product Development 101
template: post
slug: product-development-101
draft: false
featured: false
date: "2020-07-02T15:00:00.000Z"
description: How to keep it simple and build products with the end-user in mind.
cover: ./product-development-101-cover.jpeg
category: Programming
tags:
  - Product development
  - Programming
  - Digital products
---

![](/product-development-101-cover.jpeg)

Generally speaking, non-technical people are unaware of the wide array of possibilities technology has to offer and the ways their problems can be solved. Heck, they do not even think about having a problem in the first place.

That is where product people come in and offer their expertise. By observing, asking the right questions, and identifying problems, we are able to come up with solutions that have the potential to improve people's lives.

The three simple steps below will help you to build products with the end-user in mind, and not get lost in the realm of fancy frameworks, complicated features that no one needs, and the desire to ship flawless applications. Done is better than perfect.

## 1. Identify the problem

[![Photo by Per Lööv on Unsplash](/per-loov-unsplash.jpeg)](https://bit.ly/3tLUxjh)

It is tempting to look at a request, think about a solution, and immediately start getting our hands dirty to ship it. But was the original request really a problem, a short term pain or just confusion?

We do not know until we start to ask questions. Lots of them. Doing it we will be able to identify the root of the problem, and that can be totally different from the initial request.

Asking open-ended questions that help to describe the problem(for example "Do users struggle finishing purchases and why?"), instead of seeking validation for a given idea(for example "Will universal login reduce the friction of finishing purchases?") is crucial. This way we are going to be more open to different solutions and less exposed to confirmation bias.

_Our resources are limited_, so it is necessary to prioritize based on what the impact is going to be. Failing to do this could hijack our attention and lead us down the wrong path.

## 2. Ship it

The moment I realized that I am here to solve problems, and not write the most beautiful code, I started to enjoy even more what I do. I love seeing when a piece of code I shipped makes an impact.

It is a good practice to think about how the minimal viable product(or simply the "MVP") could look like. Erik Reis, in his popular book, ["The Lean Startup"](https://bit.ly/373CmMy), defined the MVP as:

> The MVP is a version of a new product which allows a team to collect the maximum amount of validated learning about customers with the least effort.

This can be done by having a discussion with your team and the different stakeholders about the MVP, define the features you want and _stay on target._ By doing this, you will be able to remind yourself about the big picture when the pressure to add a new feature is going to rise.

Before we go nuts, it is better to implement the _simplest version_ of our product and test it with _real users_. **We will save lots of time** byskipping the work on features that no one will ever use and **we will start adding value to the user** by shipping a product they can start using right away.

As I said before, _our time is limited_, so let's use it in the best possible way.

## 3. Iterate

[![Source](/iteration.png)](https://bit.ly/3rDmCHQ)

I have fallen into the mistake of trying to have the best version of the product ready for the launch countless times. And it was never efficient. There were quite a few times when we did not even release what we have built.

It is a better practice to release a usable version of the product as soon as you have it ready, and iterate after.

You do not know how your users are going to use your work until you deliver it to them and see it in action. Give them time to learn how to use it. See where they struggle. Listen to their feedback. And then start over from step one.

## Final thoughts

Product development does not need to be complicated. It is a relatively simple process that you can start mastering by implementing the three principles outlined in this article.

How do you approach product development? What is your secret to keep it simple and functional? How do you make sure that you are delivering value?

Let me know your thoughts in the comment section or reach out on any of the social listed below!

repository: robertistok/personal-website

repo_name: robertistok/personal-website


text:
# Hacker News Clone

## Description

Clone of hacker new made with vanilla Javascript to incorporate state and status concepts.

## Live

[live](https://hacker-news-clonado.netlify.app/)

branch_name: refs/heads/main


text:
[![license](https://img.shields.io/github/license/peaceiris/actions-gh-pages.svg)](https://github.com/peaceiris/actions-gh-pages/blob/master/LICENSE)
[![release](https://img.shields.io/github/release/peaceiris/actions-gh-pages.svg)](https://github.com/peaceiris/actions-gh-pages/releases/latest)
[![GitHub release date](https://img.shields.io/github/release-date/peaceiris/actions-gh-pages.svg)](https://github.com/peaceiris/actions-gh-pages/releases)

## GitHub Actions for deploying to GitHub Pages

A GitHub Action to deploy your static site to GitHub Pages with [Static Site Generators] (Hugo, MkDocs, Gatsby, GitBook, etc.)

[Static Site Generators]: https://www.staticgen.com/

## Getting started

### (1) Add deploy Key

1. Generate deploy key `ssh-keygen -t rsa -b 4096 -C<EMAIL_ADDRESS>-f gh-pages -N ""`
    - You will get 2 files: `gh-pages.pub` (public key) and `gh-pages` (private key)
2. Go to "Settings > Deploy Keys" of repository.
3. Add your public key within "Allow write access" option.
4. Go to "Settings > Secrets" of repository.
5. Add your private key as `ACTIONS_DEPLOY_KEY`

### (2) Create `main.workflow`

An example with Hugo action.

- [peaceiris/actions-hugo: GitHub Actions for Hugo extended](https://github.com/peaceiris/actions-hugo)

```hcl
workflow "GitHub Pages" {
  on = "push"
  resolves = ["deploy"]
}

action "is-branch-master" {
  uses = "actions/bin/filter@master"
  args = "branch master"
}

action "build" {
  needs = "is-branch-master"
  uses =<EMAIL_ADDRESS>  args = ["--gc", "--minify", "--cleanDestinationDir"]
}

action "deploy" {
  needs = "build"
  uses =<EMAIL_ADDRESS>  env = {
    PUBLISH_DIR = "./public"
    PUBLISH_BRANCH = "gh-pages"
  }
  secrets = ["ACTIONS_DEPLOY_KEY"]
}
```

## License

[MIT License - peaceiris/actions-gh-pages]

[MIT License - peaceiris/actions-gh-pages]: https://github.com/peaceiris/actions-gh-pages/blob/master/LICENSE

## About the author

- [peaceiris's homepage](https://peaceiris.com/)

repository: emuhedo/actions-gh-pages

repo_name: emuhedo/actions-gh-pages


text:
# Getting Started

You will need a Muse 2016 and Python installed on your computer. With the exception of some of the stimulus presentation scripts, all code will work with Python 3.

The muse-lsl library that manages connecting to Muse and recording data is incorporated into this repo as a submodule. In order to get it up and running use the following commands:

Either:

```
git clone --recursive https://github.com/neurotechx/eeg-notebooks
```

Or:

```
git clone https://github.com/neurotechx/eeg-notebooks
cd eeg-notebooks
git submodule init
git submodule update
```

Install all requirements

`pip install requirements.txt`

(See [here](http://eeg-notebooks.readthedocs.io/en/latest/setup_instructions_windows.html)

for more detailed setup instructions for windows operating systems)

To connect to your Muse and begin streaming data

`python muse-lsl/muse-lsl.py --name MUSE_YOURDEVICEID`

IMPORTANT: Leave this terminal running while you are recording data performing experiments

To visualize streaming data

`python muse-lsl/lsl-viewer.py`

IMPORTANT: If you intend to collect data for an experiment, ensure that your signal quality is "excellent" and that there is very little noise before proceeding.

### Running an experiment

With the muse-lsl.py script running, open another terminal and run

`python stimulus_presentation/PARADIGM.py -d 120 & python muse-lsl/lsl-record.py -d 12`

where `PARADIGM.py` is one of the stimulus presentation scripts described above (e.g., `generate_Visual_P300.py`).

This will launch the selected paradigm and record data for 2 minutes. Consider repeating this 6 - 10 times in order to gather enough data.

After collecting data, move your recorded data CSVs to the data folder. Currently, notebook analysis scripts work with a `experiment/type/subjectNumber/sessionNumber` directory structure.

Open the Jupyter notebook relevant to the experiment your performed (e.g. `P300 with Muse.ipynb`) to analyze your data

repository: stephenrho/eeg-notebooks

repo_name: stephenrho/eeg-notebooks


text:
# Component parameters

Components support different parameters depending on the component type. Refer to individual component documentation to see which parameters are supported.

#### Documentation of the most commonly supported parameters that apply to most elements

`style` This is the most common parameter and defines the style class name. All components support this, but not all style parameters might not be supported in some edge cases (video for example).

`onclick` Second most commonly used parameter, which defines an action upon click. All components support this. This can be either one onclick object obtained with any of the `$this->getOnclick` helpers or an array of several onclicks. When array is defined, client will execute commands in order they are defined in the array. IMPORTANT NOTE HERE: some onclicks return an array (most notably route when it has saveparameters), whereas most onclicks will return and object.

`variable` Used by text, form elements and images. This helps client tie the data. For example, if you set a variable outside of the component, when variable is defined the value would get updated immediately. Common example case is where you have a clickable field which reveals a selector element that sets the value.

NOTE: you can use either actual variable id's together with $this->getVariableId('name') or give them as strings. If the variable is defined for the app, the client would always send id instead of the string. All async functionalities require that the variable exists for the app and they need to be defined by id, NOT STRING.

`id` Id of the element. This is used when showing or hiding elements with onclick, by swipestack and swipe components. If you have multiple swipe components in the view with a swipe indicator, they must have id's defiend. If you only have one swipe element, the swipe navigation will default to that even without id.

#### Form field text component parameters

`hint` Shows a hint on the background of "field-text" or "field-textview" if the components have no content. Uses the form style with opacity set to 0.6.

`activation` Initially or keep-open. Initially means that the text field is in focus when opening the view, keep-open will keep the focus in the form field and keyboard open even when the view is submitted.

`submit_menu_id` Menuid to submit when submit_on_entry is defined. This is available for your model as $this->getMenuId();

`submit_on_entry` Submit view when text is edited in the field. This can be used to make suggestive search for example. Note that filter is often a better option as it doesn't require turnaround to the server.

`update_on_entry` Instructs the mobile client to update all linked components when the component value changes. Components are linked by setting the same "variable".

`filter_on_entry` It can be either 1 or 0. When this flag is set on a field-text components the mobile client will filter out all 1st level components that has "filter" set and "filter" does not contain the current text in the field-text component.

`input_type` phone, number, name, uppercase, lowercase, email

`autocorrect` Either 0 or 1. Default is 0,

`value` Initial value of the field.

`activation` Initially or keep-open. Initially means that the text field is in focus when opening the view, keep-open will keep the focus in the form field and keyboard open even when the view is submitted.

`maxlength` Max length of the field content. Number of characters, also whitespace is counted.

`disable_onclick_when_keypad_is_on` This will disable all clickable items as long as the keyboard is open.

#### Selectors (checkbox and radio button -like functionality)

Example of defining a select element:

```
    $selectstate_female = array('variable_value' => "male",'style' => 'selector_role_selected','allow_unselect' => 1,'animation' => 'fade');
    $selectstate_male = array('variable_value' => "female",'style' => 'selector_role_selected','allow_unselect' => 1,'animation' => 'fade');

    $col[] = $this->getText('{#female#}',array('variable' => 'gender','selected_state' => $selectstate_female,'style' => 'selector_role', 'active' => 1));
    $col[] = $this->getVerticalSpacer('10%');
    $col[] = $this->getText('{#male#}',array('variable' => 'gender','selected_state' => $selectstate_male,'style' => 'selector_role'));

    $this->data->footer[] = $this->getRow($col,array('margin' => '14 40 31 40','text-align' => 'center'));

```

`selected_state` Parameters for this compoenent when its selected

`allow_unselect` Whether the option can be unselected

`animation` Fade or none

`active` If the element is currently active

`other_variables` An array with variable names. Its used when a component has "selected_state" and when selected it should also select all other components that has variable name that matches and item in this list

If the elements are using the same variable, it behaves like a radio button, if they have different variables, it acts as checkboxes.

#### Image component parameters
`image_fallback` when clicked, change to this image immediately

`lazy` can load after view, shows a loader

`tap_to_open` will open a full screen image when clicked

`tap_image` image asset name to be used on the full screen view

#### Map component parameters
Map component uses Google maps to display a map. Note that you need to define Google Maps API key in your app settings for this to work. Please refer to Google documentation:

* https://developers.google.com/maps/documentation/ios-sdk/map
* https://developers.google.com/maps/documentation/ios-sdk/marker

`position` Lat, lon of the map position.

`zoom` Zoom level.

`map_type` roadmap, satellite, hybrid, terrain.

`markers` Array of map markers

#### Video component parameters
`autostart` Starts video when entering the view.

`showplayer` Shows player controls.

`loop` Loops the video.

#### Calendar component parameters
`date` Unix time

`date_format` For example MM / dd / yyyy

`show_only_current_month` Shows only the current month and won't allow navigating between months

`disable_swipe` Disables the swipe in the calendar component and replaces it with buttons

`selection_style` Style name

`weekend_style` Style name

`weekdays_style` Style name

`header_style` Style name

`today_style` Style name

#### Swipe component specific parameters

`remember_position` Remembers the position of the swiped page between refreshes and when navigating out from the action.

`hide_scrollbar` Hides bottom scroll bar

`topbar_title` Changes the action's top bar. This must be defined for the main level of the element which is inside the swipe.

`animation` nudge. If this is set, the swipe component will make a small nudge movment when entering the view. This will hint user that the content is swipable.

#### Swipe naviagation parameters

`active_color` This is used to specify the color of the active dot in "swipe-navigation" component.
`inactive_color` This is used to specify the color of the inactive dots in "swipe-navigation" component

#### Swipestack component specific parameters

Swipe component is a very powerful component, which allows the actions to be recorded by the backend in an asynchronous manner. This provides seamless user experience when swiping items in the swipe stack.

`leftswipeid` Menuid to call when swiping an element left. Menuid is available with $this->getMenuId();

`rightswipeid` Menuid to call when swiping an element right. Menuid is available with $this->getMenuId();

`upswipeid` Menuid to call when swiping an element up. Menuid is available with $this->getMenuId();

`downswipeid` Menuid to call when swiping an element down. Menuid is available with $this->getMenuId();

`prevswipeid` Is set when the item is swiped. Its automatically assigned by the server to either leftswipeid or rightswipeid depending on which direction the item was swiped.

`backswipeid` Menuid to call when returning an element back from the swipe_back_content.

`overlay_right` A component that will be rendered on top of the card that the user is swiping.

`overlay_left` A component that will be rendered on top of the card that the user is swiping.

`overlay_up` A component that will be rendered on top of the card that the user is swiping.

`overlay_down` A component that will be rendered on top of the card that the user is swiping.

`swipe_back_content` An array with components that the user can swipe back. When the user do "swipe-back" the first item from this array will be returned to the 'swipestack' component with an animation.

#### Used by swipe and scrolling content

Dynamic swipe component can call the server with following parameters on $_REQUEST:
`swid`
`world_ending`
`backwards`
`merge_before`

Component parameters:

`dynamic` Defines the element to be dynamically loading

`world_ending` Yes, really, don't ask about parameter naming. This is the menuid that gets called when we are near the cached content ending. This is a que for the backend to provide more items.

`id` Id of the swipe container, needed for dynamic swipes

`item_scale` set this to 1 to have scaling effect when swiping

`transition` swipe

`preserve_position` preserve the swipe position between action refreshes

`initial_swipe_id` items need to have swipe_id defined in order to use this. Opens the swipestack on this page.

`item_width` width of the items

`remember_position` used by non-dynamic swipes. Remembers users position between action refreshes.

`merge_data` If this is set to 1, client will merge the new data based on swipe_id's. This way the backend doesn't need to fetch the entire swipe stack, only new items.

Best example of the swipestack you can find from action Mcalendar.

#### Advertising component parameters

`ad_size` Sizes are:
- 'banner' => '{%small%} (320x50)',
- 'large' => '{%large%} (320x100)',
- 'rectangle' => '{%box%} (300x250)',

`ad_id` required, ID as defined in the Google Ads console or AdColony

#### Slider component parameters

Remember to add `variable` for the slider. If you have also `variable2` defined, this will display a range slider.

`min_value` Numeric. Minimum value to set.

`max_value` Numeric. Maximum value to set.

`step` Numeric. In what increments the slider moves.

`hide_tooltip` 1 or 0 whether the value is hidden when dragging the value

`tooltip_prefix` Prefix for the value. For example currency.

`tooltip_suffix` Suffix for the value. For example currency.

`track_height` Height of the slider itself, excluding thumbs.

`left_track_color` Hex. Color of the selected part.

`right_track_color` Hex. Color of the unselected part.

`thumb_color` Color for the slider's handle.

`thumb_image` Use image instead of the default slider handle.

`thumb_height` Height for the slider's handle.

##### Applies only for range slider

`variable2` Variable where second slider from the range slider is saved.

`min_range` Numeric. Minimum range for range slider

`max_range` Numeric. Maximum range for range slider

#### Progress bar component parameters

`text_content` Text content shown inside the bar. Styling the text is done by giving style parameters for the element itself.

`progress_image` Use image instead of the color for the progress bar itself.

`progress_color` Hex. Color for the inactive part of the progess bar.

`track_image` Use image instead of color for the active part.

`track_color` Hex. Color for the active part of the progess bar.

#### Infinite scrolling content

`next_page_id` You can access this with $this->getNextPageId() in the model. Use this to retrieve paged results.

`lazy` Lazy loading of the content, where we reveal the next page even if all content might not be fully loaded yet.

`show_loader` Whether to show the loader when reaching the end of the current page.

#### Timer component

`timer_id` Id of the timer component. This needs to be defined, client uses this to keep track of the time on the client side.

`submit_menu_id` Menuid to call when countdown reaches zero

`mode` countdown. Count down instead of up. Default is to count up.


text:
# Examples

Here are some examples on how to apply the 3 Musketeers for different kinds of applications.

* [Hello, World!][linkHelloWorld] is the simplest example showing the 3 Musketeers in action.
* [3musketeers.io][link3Musketeers] uses 3 Musketeers to build VuePress website and deploy to Netlify with GitHub Actions.
* [flemay/cookiecutter][linkFlemayCookiecutter] is a docker image that is built, tested, and deployed to Docker Hub with GitLab CI/CD. The pipeline uses Docker in Docker (DinD) with the image `flemay/musketeers`.
* [flemay/musketeers][linkFlemayMusketeers] is a docker image that is built, tested, and deployed with TravisCI to Docker Hub.
* [Echo][linkEcho] is a Cookiecutter template for a basic example that echoes the value of an environment variable.

* [Go command line application][linkGoCommandLineApplication] is a Cookiecutter template for a CLI go application.

[linkHelloWorld]: ../docs/#hello-world
[linkEcho]: https://github.com/3musketeersio/cookiecutter-musketeers-echo
[link3Musketeers]: https://github.com/flemay/3musketeers
[linkLambdaGoServerless]: https://github.com/3musketeersio/cookiecutter-musketeers-lambda-go-serverless
[linkGoCommandLineApplication]: https://github.com/3musketeersio/cookiecutter-musketeers-go
[linkFlemayCookiecutter]: https://gitlab.com/flemay/docker-cookiecutter
[linkFlemayMusketeers]: https://github.com/flemay/docker-musketeers


text:
---
layout: page
title: Code tabs
navigation: 2
---

# Contents
{:.no_toc}
* TOC
{:toc}

# Code tabs
Default highlighting works:
```python
def func():
    pass
```

But you can also add examples in several different languages:
## One
{% codetabs %}

{% codetab Java %}
```java
System.out.println("Hello, world!");
```
{% endcodetab %}

{% codetab Go %}
```go
fmt.Println("Hello, world!")
```
{% endcodetab %}

{% codetab Python %}
```python
def func(param):
    pass

print("Hello, world!")
```
{% endcodetab %}

{% endcodetabs %}

## Two

{% codetabs %}

{% codetab Java %}
```java
System.out.println("Hello, world!");
```
{% endcodetab %}

{% codetab Go %}
```go
fmt.Println("Hello, world!")
```
{% endcodetab %}

{% codetab Python %}
```python
def func(param):
    pass

print("Hello, world!")
```
{% endcodetab %}

{% endcodetabs %}

And then when you select the language in one of the tabs, it is automatically selected in the other. Also, the selected language is remembered in `localStorage`, so that it works between pages and page refreshes.

# Markdown
All the rest of the markdown features shall work fine too.
## H2
### H3
#### H4
This is a sample text with `quote` and other *italic* and **bold** text.

- one
    - one
- two

1. One
2. Two

> Blockquote

- [x]  @mentions, #refs, [links](), **formatting**, and <del>tags</del> supported
- [x]  list syntax required (any unordered or ordered list supported)
- [x]  this is a complete item
- [ ]  this is an incomplete item

First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column

repository: pgenevski/jekyll-codetabs

repo_name: pgenevski/jekyll-codetabs


text:
English | [中文](./README-CN.md)

# Introductions

An alternative way to explore and develop with [`Hyperf`](https://github.com/hyperf/hyperf).

# Requirements

 - `Docker`
 - `docker-compose`

# Usage

- Generate Docker image `docker-compose build`
- Install `composer.json` dependencies `docker-compose run --rm hyperf-web "composer install --no-dev"`
- Start service `docker-compose up -d`
- Visite: usually `http://<IP_ADDRESS>:9501` on `Windows`, `http://<IP_ADDRESS>:9501` on `Linux`/`Mac`

# Tips

- On `Windows`, put your code in path `C:\Users\{USERANME}`, or docker volume mount will be failed
- When `Dockerfile` has a change, you need to rebuild docker image `docker-compose build`

repository: wueason/hyperf-startkit

repo_name: wueason/hyperf-startkit


text:
# 11 - Advanced Topics #
______________________________________________________________

These are just a brief breakdown on topics you can check out for Ansible. There are also no labs here, you can further explore the areas that interest you.

You can check out more details in the [Ansible Documentation page](https://docs.ansible.com/)

- Windows Server
- Ansible-Galaxy
- Patterns
- Dynamic Inventory
- Developing Custom Modules

_______________________________________________________________

## PREPARING A WINDOWS ENVIRONMENT ##

Recall that the **Ansible Controller** can only be run on Linux. However, Windows machines can be used as target machines, thus they can be part of automation.

For Ansible to connect to a Windows machine, we should use **winrm**. This may not always be enable by default in Windows machines. You may follow the following steps to setup winrm on the Windows machines.

Remember that Ansible is *agentless*, so you won't need to install anything from Ansible on the Windows machine.

1.  Install the **pywinrm** module on the Ansible controller by running:

        sudo pip install "pywinrm>=0.2.2"

2. Next is to install winrm on the Windows Server. You can use the powershell script provided by Ansible. See more details about setting up a Windows Host [here](https://docs.ansible.com/ansible/2.5/user_guide/windows_setup.html)

        example/scripts/**ConfigureRemotingForAnsible.ps1**

3.  There are different modes of authentication that you can also set up:

    - Basic
    - Certificate-based
    - Kerberos
    - NTLP
    - CredSSP

______________________________________________________________

## ANSIBLE GALAXY ##

This is a free site for sharing all kinds of comuunity-develoepd Ansible roles. This is a great way to start on your automation projects. You can visit theit site [here.](https://galaxy.ansible.com/)

______________________________________________________________

## PATTERNS ##

AN example of this is specifying the **hosts**. We can specify one hosts a time, or we can also specify multiple hosts and groups by separating them with a comma (,).

```yaml
-
    name: Example Play
    hosts: host1, host2, group1
```
We can also use wildcard patterns. Here we can run the playbook on all hosts that start with "server" and hosts that ends with ".company.com"

```yaml
-
    name: Example Play 2
    hosts: server*, *.company.com
```
You can find out more about patterns in the [Ansible documentation page](https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html)

______________________________________________________________

## DYNAMIC INVENTORY ##

Recall that we can define all or hosts in the default inventory filem */etc/ansible/hosts*. We can also create a custom inventory file. When you run the playbook, you'll also need to specify the inventory file.

    ansible-playbook sample.yaml -i inventory.txt

Both of these are good but these are **static** methods and you'll have to change them manually. If you'll have to integrate Ansible with other sources in your environment, you will need to make this inventory dynamic.

To do this, you can create a script and specify it when you run the playbook:

    ansible-playbook sample.yaml -i inventory.py

This script will be responsible of getting information from the sources in your environments and providing Ansible with the details.

______________________________________________________________

## DEVELOPING CUSTOM MODULES ##

Modules are simple pre-built python scripts that perform specific actions. If you can't find a moduel that satisfy your requirement, you cand develop your own custom module.

To do this you just jave to write your own python program and place it on the modules directory on your server. Note that the program has to follow a **certain format**. You can get at the [Ansible documentation page](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html).

______________________________________________________________


text:
# he-nft-counter
Count NFTs of certain types owned by users on Hive-Engine

# Editing

Lines 8 - 14 are all you should need to edit for standard Hive-Engine:

```js
const NFT_SYMBOL = "HKFARM"; // Your NFT Symbol
const EXPORT = true; // Export to file? true = Export, false = no

// Return true to count, false to ignore
function limiter(nft) {
    return nft.properties.TYPE.toLowerCase() ===  "plot";
}
```

I've commented it so you should be able to tell what each thing does :D

repository: CADawg/he-nft-counter

repo_name: CADawg/he-nft-counter


text:
---
title: 'Exception Handling in Ruby – a Little Surprise'
author: Justin Ball
layout: post
permalink: /2010/11/30/exception-handling-in-ruby-a-little-surprise/
tags:
  - Programming
  - Ruby On Rails
---

I've got a rake task that includes a section where I do something like this:

begin
  # Do some things
rescue => ex
   puts "Error: #{ex}"
end

I know that typically you want to be specific about the errors that you catch, but in this case I just want to move on. The things that didn't happen on this pass will get caught the next time around. It turns out that this code block won't always catch every error. It took some serious thinking to figure out why.  Network time out errors are not a subclass of StandardError and thus will not be caught in the block above. Instead you have to put together a block like this:

begin
  # Do some things
rescue => ex
   puts "Error: #{ex}"
rescue Timeout::Error => e
  puts "Timeout Error: #{e}"
end

That will catch the Timeout error and allow you to deal with it appropriately.


text:
    <meta itemprop="name" content="TensorFlow Datasets" />

  <meta itemprop="name" content="uc_merced" />
  <meta itemprop="description" content="UC Merced is a 21 class land use remote sensing image dataset, with 100 images
per class. The images were manually extracted from large images from the USGS
National Map Urban Area Imagery collection for various urban areas around the
country. The pixel resolution of this public domain imagery is 0.3 m.

While most images are 256x256 pixels, there are 44 images with different shape.

To use this dataset:

```python
import tensorflow_datasets as tfds

ds = tfds.load('uc_merced', split='train')
for ex in ds.take(4):
  print(ex)
```

See [the guide](https://www.tensorflow.org/datasets/overview) for more
informations on [tensorflow_datasets](https://www.tensorflow.org/datasets).

" />
  <meta itemprop="url" content="https://www.tensorflow.org/datasets/catalog/uc_merced" />
  <meta itemprop="sameAs" content="http://weegee.vision.ucmerced.edu/datasets/landuse.html" />
  <meta itemprop="citation" content="@InProceedings{Nilsback08,
   author = "Yang, Yi and Newsam, Shawn",
   title = "Bag-Of-Visual-Words and Spatial Extensions for Land-Use Classification",
   booktitle = "ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems (ACM GIS)",
   year = "2010",
}" />

# `uc_merced`

*   **Description**:

UC Merced is a 21 class land use remote sensing image dataset, with 100 images
per class. The images were manually extracted from large images from the USGS
National Map Urban Area Imagery collection for various urban areas around the
country. The pixel resolution of this public domain imagery is 0.3 m.

While most images are 256x256 pixels, there are 44 images with different shape.

*   **Homepage**:
    [http://weegee.vision.ucmerced.edu/datasets/landuse.html](http://weegee.vision.ucmerced.edu/datasets/landuse.html)

*   **Source code**:
    [`tfds.image_classification.UcMerced`](https://github.com/tensorflow/datasets/tree/master/tensorflow_datasets/image_classification/uc_merced.py)

*   **Versions**:

    *   **`2.0.0`** (default): New split API
        (https://tensorflow.org/datasets/splits)

*   **Download size**: `317.07 MiB`

*   **Dataset size**: `Unknown size`

*   **Auto-cached**
    ([documentation](https://www.tensorflow.org/datasets/performances#auto-caching)):
    Unknown

*   **Splits**:

Split     | Examples
:-------- | -------:
`'train'` | 2,100

*   **Features**:

```python
FeaturesDict({
    'filename': Text(shape=(), dtype=tf.string),
    'image': Image(shape=(None, None, 3), dtype=tf.uint8),
    'label': ClassLabel(shape=(), dtype=tf.int64, num_classes=21),
})
```

*   **Supervised keys** (See
    [`as_supervised` doc](https://www.tensorflow.org/datasets/api_docs/python/tfds/load#args)):
    `('image', 'label')`

*   **Citation**:

```
@InProceedings{Nilsback08,
   author = "Yang, Yi and Newsam, Shawn",
   title = "Bag-Of-Visual-Words and Spatial Extensions for Land-Use Classification",
   booktitle = "ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems (ACM GIS)",
   year = "2010",
}
```

*   **Visualization**
    ([tfds.show_examples](https://www.tensorflow.org/datasets/api_docs/python/tfds/visualization/show_examples)):

repository: rushabh-v/datasets

repo_name: rushabh-v/datasets