<![CDATA[OhMyBrew!]]>https://ohmybrew.com/https://ohmybrew.com/favicon.pngOhMyBrew!https://ohmybrew.com/Ghost 2.10Fri, 19 Jul 2019 16:58:34 GMT60<![CDATA[Vuex & Data: Keeping It Clean]]>Introduction

Vuex is a state management library, a centralized storage of data for your whole application. Its well documented, beautiful, and easy to use with Vue. The part I want to talk about today is the data portion.

I have increasingly seen cases where the data state of Vuex gets

]]>
https://ohmybrew.com/a-small-vuex-tip/5d31ee515be84050aa1577c0Fri, 19 Jul 2019 16:44:52 GMTIntroductionVuex & Data: Keeping It Clean

Vuex is a state management library, a centralized storage of data for your whole application. Its well documented, beautiful, and easy to use with Vue. The part I want to talk about today is the data portion.

I have increasingly seen cases where the data state of Vuex gets transformed and represents something more than just plain-old data; that's a problem in the long run.

The Problem

A simple example...

Step 1

An external API request is sent out through an action to get a list of books.

Step 2

That book data is then sent to the mutation handler where the developer would map the data to a model class: const bookCollection = books.map(book => new Book(book));.

Step 3

This transformed data gets committed to the state afterwards with state.books = bookCollection;.

All-Together

At first, this seems convenient to the developer, because in any part of their code, they can utilize their models such as: const authorsNotOnSale = state.books.filter(book => !book.isOnSale()).map(book => book.getAuthor()).

But, what happens when you want to serialize that data to JSON? Store it somewhere else outside of Vuex? Such as using a library like vuex-persist?

You'll immidately loose all those nice model functions you've built out and you can not easily restore the state because its more than just data at this point.

The Solution

The proper solution would be to utilize Vuex getters to transform that data into something more usable in your application.

const bookCollection = state => state.books.map(book => new Book(book));

Keep the data clean, lean, and plain. Think of the data this way: can I serialize this? If the answer is no, you may need to dig into why.


Photo credit: Mathew Schwartz

]]>
<![CDATA[FOSS Alternatives for Android]]>These days, privacy and security are out the window. In 2018 and already during 2019, we've seen some of the biggest exploits and privacy invasion to date; everything from people's bank records being leaked due to improper security, to the various scandals of Facebook, and even our home devices such

]]>
https://ohmybrew.com/foss-alternatives-for-android/5cec39c4659a134bdbe1f59dTue, 28 May 2019 13:28:54 GMTThese days, privacy and security are out the window. In 2018 and already during 2019, we've seen some of the biggest exploits and privacy invasion to date; everything from people's bank records being leaked due to improper security, to the various scandals of Facebook, and even our home devices such a basic TV tracking everything you do.

Exodus is a great tool for Android (available on web or F-Droid), allowing you to scan your installed applications and get a full report on what permissions the application asks for and what trackers it has built in.

Below, I'll list some of my choices for alternatives that are free (as in freedom) and protect your privacy.

Lawnchair V2

Source: XDS Developers

This is a Pixel-like launcher that is highly customizable. Although its been in "alpha" stage for quite some time, I've yet to experience any bugs with it and is very stable based on my experience. It is also actively developed, with updates being pushed out weekly.

Exodus - Download

KISS Launcher

Source: APK Fun

Another great launcher which takes a whole new approach is KISS. KISS is a geared to be a very minimal launcher with simply lists your frequent apps on the bottom row and your main screen consists of all your previous/recent apps accessed. Its extremely lightweight, out-of-the-way, and a fresh experience.

Exodus - Download

Fennec / Klar

Source: F-Droid

Fennec is the latest release of "Firefox for Android" with proprietary bits removed. Firefox is rock solid on Android alternative to Chrome. Not only is it more privacy-friendly but it allows for extensions to be installed such as uBlock Origin, HTTPS Everywhere, etc. Firefox Sync also works between devices flawlessly and supports integration with KDE Konnect. Klar, similar to Fennec, is the "Firefox Focus for Android" version with proprietary bits removed.

Download (Fennec) – Download (Klar)

TOR

Source: GHacks

TOR of course, allows for the most privacy. TOR is a network powered by other TOR users. You become anonymous as you're routed through different relay connections before hitting the final destination. The browser itself is a modified Firefox release with a wealth of tools to help your remain anonymous to the "web lords", tracking, and more.

AnySoftKeyboard

Source: F-Droid

GBoard "phones home" to build better suggestions about your typing, but who knows what else it's storing about what you type? I have limited experience with other keyboards, however this one caught my eye and I needed not to look any farther.

AnySoftKeyboard is completely customizable with a wealth of options, gestures (including swipe-to-type), many themes (I find the "Dark ASOP" theme the most GBoard-like), and extensions. Its actively developed and features alternative languages through extensions as well.

Exodus - Download

Markor

Source: F-Droid

Markor is a feature-rich markdown editor with support for todo.txt. Nothing is stored in the cloud but because everything is offline it supports any sync client such as OwnCloud, NextCloud, Seafile, Syncthing, or anything else which simply watches a directory.

Markor is great for storing notes, draft blog posts, recipes or anything you can store in markdown or plaintext format.

Exodus - Download

Simple File Manager

Source: F-Droid

Simple File Manager provides an basic interface for managing your files stored locally and on any SD card attached to the phone. It features a quick search, bookmarking, password protection, and more.

Exodus - Download

Syncthing

Source: F-Droid

Syncthing replaces proprietary sync and cloud services with something open, trustworthy and decentralized. Putting you in control of your files and keeping them out of the cloud. You have the ability to add approved devices to share folders on any device with any other device. It has support for iOS, Android, and comes with a handy web-client for easier configuration. As well, it comes with several built-in options for file versioning.

Exodus - Download

Tasks

Source: Google Play

Tasks is a open source fork of the Astrid app. A great material-designed app to keep your self on track. Its full featured with categories, priorities, location-based tasks, voice clips, and more.

Exodus - Download

Bitwarden

Source: Google Play

Bitwarden is a cross-platform password management tool. Its easy to use and can help you store logins for websites, logins for databases, logins for servers, credit cards, notes, and more. It also features built-in TOTP for two-factor authentication. Extension for Firefox is also available.

Exodus - Download

FreeOTP+

Source: Github

FreeOTP is a two-factor authentication (2FA) application for systems  utilizing one-time password protocols (OTP). Tokens can be added easily  by scanning a QR-code or by manually entering in the token  configuration.

FreeOTP implements open standards. This means that  no proprietary server-side component is necessary: use any server-side  component that implements these standards

Exodus - Download

QKSMS

Source: Github

QKSMS is an open source, material designed, SMS/MMS app. It features a customizable interface, with dark mode, scheduled messages, message pinning, searching, media access, and more.

Exodus - Download

OpenHub

Source: Github

An open source GitHub Android client app, faster and concise. It allows you to manage your profile, repositories, issues, and more. The only downside I find is theres no difference inside the app for what is an issue and what is a PR. So if someone submits a PR, you can not view the changes from the app.

Exodus - Download

OpenSync

Source: Google Play

By default, Android does not support CalDAV/CardDAV (probably because Google wants you stuck on their services). This simple app allows you to connect to DAV services such as Mailbox.org, PrivateEmail.com, FastMail.com, and more. You're able to pull in and sync two-way: your contacts, your calendars, your tasks (via calendar), and mail.

Exodus - Download

RedMoon

Source: Phone Arena

RedMoon is a "night shift"-like app which filters out blue light at night. This helps your eyes at night, and prevents the blue light from interfering with production of Melatonin. It features a schedule, or location-based scheduling, with several features for screen color, temperature and more.

Exodus - Download

ScreenCam

Source: Play Store

ScreenCam allows you to record your screen (and voice). It features settings to pause/resume recordings, bit rates, resolutions, audio sources, and more.

Exodus - Download


Of cource, there's more open source apps for calendar, email, etc. Explore and find out what you can replace on your phone with a more open source and privacy-abiding alternatives.

]]>
<![CDATA[Go Is Beauty, In Short]]>I've been coding with Golang in my spare time for the past year. I've released a few side projects such as a simple blockchain implementation, a webhook validator for Shopify, a Python clone of with, and other nick-nacks. Unfourtunately, I haven't had the chance to use it a whole lot

]]>
https://ohmybrew.com/go/5cbd242b4d87ad52707c1017Mon, 22 Apr 2019 02:32:29 GMT

I've been coding with Golang in my spare time for the past year. I've released a few side projects such as a simple blockchain implementation, a webhook validator for Shopify, a Python clone of with, and other nick-nacks. Unfourtunately, I haven't had the chance to use it a whole lot during working hours.

Go is a strange beast. To a new comer, it has an odd syntax for methods, loops, doesn't come with built-in collection methods, its plain-jane control flow, and to top it off.. its not functional and its not object-oriented.

I won't get into depths of Go, but I just wanted to shout out to its beauty in it's strangeness in this post. It allows you to code freely in a logical manner, with the power of interfaces and structs that I've not yet seen in another language I've personally worked with.

I love how it also does not hold you hand. You're free to do what you please and its very bare-bones in a sense which gives you a good base to build from (example: the built in testing package has no assertions). Its also hella fast.. the compile times and plain processing abilities are phenominal.

Theres a lot of built in tools like gofmt which ensures your code is formatted a certain way and the build system, the ability to build targetted binaries for systems (even exes!) quickly.

The community is growing rapidly and many tools are popping up, and many tools are being rewritten to Go. I'm excited to see its future and continue working with it more, hopefully the next few versions will fix some module issues and introduce generics.


Photo credit: strichpunkt

]]>
<![CDATA[De-Servicing Life: Revised]]>A few months ago, I began a journey of mainly de-Googleing, but other services as well. I've made some good and bad choices in terms of alternatives for myself so I have begun revising my choices.

Drive Storage

Provider

Previously, I chose pCloud, mainly due to their Linux support. They

]]>
https://ohmybrew.com/de-servicing-life-revised/5c758423dfc1f8095538cfd5Tue, 26 Feb 2019 20:39:03 GMT

A few months ago, I began a journey of mainly de-Googleing, but other services as well. I've made some good and bad choices in terms of alternatives for myself so I have begun revising my choices.

Drive Storage

Provider

Previously, I chose pCloud, mainly due to their Linux support. They have a Linux client which mounts as a standard drive. Using it for over a month, I had no issues. Its desktop app and Android app work flawlessly. Their pricing is also really fair.

However, through an Exodus scan, I found it used several trackers including Facebook specific ones (even the Facebook SSO SDK). I emailed their support about this privacy concern, twice, and received a complete "robot response" back after a couple weeks of wait. They simply stated they can not remove it and ensured its safe — Goodbye!

I considered jumping to Sync next, which is a truly great Canadian-based service focused on privacy and security of your data. They have great pricing as well, similar to pCloud.

Apps

However, I had an itch and decided to go the self-hosted route. Using my Pi 1 Model B, I attempted to install NextCloud. Yes, I knew of the performance issues with NextCloud on Pi, but I didn't care at the time — I was determined.

In practice though, it was true, the thing is a beast to try and run on a little 700mhz CPU with <1GB RAM board... I had to bail on it. Of course, I could purchase a DigitalOcean server to host NextCloud 1-click, but at this point I was still determined to keep it self-hosted.

I then discovered Syncthing. Syncthing has a large following and its open source, with clients for all the major platforms. It works by syncing folders you choose, to only the devices you choose in a secure way. This means every device you share that folder to, will get a copy of the same data synced. It also offers several revision control options. I haven been using it now for over a month to hold my data (of course with regular backups) and have had no issues, plus everything is self-hosted this way!

Solution: Desktop & Mobile (Syncthing)

Communication

Provider

I'm still with the same private email hosting provider, which handles my mail well, calendar, and contacts; through CalDav and CardDav.

The only downside is no automated Birthdays & Events calendar like other services generate based on your contacts. Luckily, I found this app, "Contact Events & Birthdays FREE". It will list our any events in your contacts... for birthdays, it'll say how far away the birthday is, plus the person's age, it will also list out any anniversaries. Further, it will notify you ahead of time. It has a solid privacy policy, and sniffing the requests it doesn't seem to have anything out of the ordinary.

Solution: Remained the same

Apps

On mobile, I tried a lot of options but some failed to work well with my work email (gSuite), or some plain didn't work. K9, which I do like because its open source, hasn't been updated in ages, the UI makes it hard to read and navigate. MailDroid was a good one as well, however I had trouble with it loading and parsing attachments, its notifications didn't seem to come in correctly as well. Nine, while praised, is $25; it works well but I am not sure I will commit to it yet.

So for now, I'm stuck with stock gMail app still.

On the desktop, I've moved over to Evolution which seems to work for my personal and work quite well. A few bugs here and there but I can get around them.

Solution: Mobile (None) — Desktop (Evolution)

Office Suite

I have fully moved off of using Google to manage my documents. I now use LibreOffice and simple Markdown documents where I can with Typora.

With Syncthing running, I can edit documents on my computer and it will sync to my devices. For Markdown, I use Typora on the desktop and on Android I use an app called Markor.

The only thing I can not find is an open source office suite for Android. Previous I tried PolarisOffice but it's riddled with ads and trackers.

For todo lists, I moved away finally from Todoist. I regular use todo list but I don't need anything heavy. I settled on a simple todo.txt file synced with Syncthing. I am able to edit this on desktop and mobile through Markor (which has todo.txt support built in).

Solution: Mobile (Markor, but no Office Suite yet) — Desktop ( LibreOffice + Typora)

Backups

I am still self-hosting... I regularly run bash scripts monthly to gather all the data I need, compress it, and sync it (through Syncthing) to an external drive as well as my Pi. With multiple copies and drives, I feel safe in this regard.

Solution: Remained the same

Photos

Sadly, no update here. Still stuck on Google Photos. I am investigating building my own solution using face_recognition library for Python. With some initial code I have some good success, the problem is finding the time to code the thing.

Solution: None

Misc

Other than that, I run blocking on all my desktop and mobile browsers. I have also setup Blokada on my Android. Blokada is open source, available on F-Droid and works by creating a local VPN on your device to run requests through. It will block tracking domains, ad domains, and more, instantly. I no longer see ads on any webpage or app I use, its successfully blocked over 10,000 of these requests for me so far in a month!

For RSS feeds, I have dropped Feedly. I now use a synced OPML list for desktop and devices. On desktop I use QuiteRSS which is fully featured and a Thunderbird-like interface to it for managing articles. On mobile, I am using Fylm, which is available on F-Droid and open source. The only downside is not having synced what was alread read or not read, but its fairly easy for me to find the point of where I left off.

I'm slowly trying to move over everything else remaining to open source apps if possible and am almost complete in my journey to de-service myself... cheers!


Photo credit: Mael BALLAND

]]>
<![CDATA[2018 Self Reflection]]>Its a couple months into 2019 already! I sat down and thought about all I've done in 2018 in regards to my digital landscape. On initial spark of this, I didn't think of much therefore, I didn't do much; but, I was wrong!

Software

Open Source

During last year I

]]>
https://ohmybrew.com/2018-self-reflection/5c5b28d39864c66c144f7ad5Wed, 06 Feb 2019 19:09:24 GMTIts a couple months into 2019 already! I sat down and thought about all I've done in 2018 in regards to my digital landscape. On initial spark of this, I didn't think of much therefore, I didn't do much; but, I was wrong!

Software

Open Source

During last year I really hunkered down and focused on my open source projects.

A few silly ones like movie-barcode, CloudApp-Bash, or With and some more important ones, which have gained some popularity, such as Laravel Shopify and Basic Shopify API.

Focusing on my open source work has not only allowed me to refine my existing public code (which some of it has aged), keep self-improving, but also help others who've faced similar issues.

In regards to Laravel Shopify in particular, I hinged on learning the core of Laravel, and coming from a previous Symfony background, this was not hard - just different. Laravel feels more like Rails for PHP, which I do love Rails so I instantly fell in love. Laravel was missing a decent Shopify boilerplate package at the time so I created the package from the ground-up to follow similar practices to how Rails' version, shopify_app gem does.

It has since gained a lot of popularity with many helpful contributors both in pull requests and general questions people post in the issue section. This, in-conjunction with Basic Shopify API package, have allowed many companies (based on their personal thank you emails to me) to create Laravel-powered Shopify apps fairly quickly, letting them focus on their apps code and not the setup.

Open source ecosystems are always great to be involved with. I'm glad I've had the late nights this year to give back to it.

Operating

Its been a hectic year bouncing between operating systems. As a long time Linux user, I broke the streak in 2014 when I purchased my Macbook. However, last year my Macbook finally hit the grave and I purchased a Thinkpad T580 to replace it (with some great specs too!), leading me to use Windows for a few months, but now I'm back on Linux!

Thankfully for software like Vagrant, Docker, WSL, VSCode, and more, my productivity hasn't been impacted between these transitions since mostly everything I write these days is either fairly portable or easily setup on another system.

I've opted for PopOS on my T580 given its great support for dual graphics cards and customizations. I even have a recent post outlining some steps I took to optimize the T580 for daily-driver usage.

Code

Besides moving away from Ruby/Rails and focusing back to PHP/Laravel/Symfony, I've also taken a great focus on modern Javascript/Node and Typescript.

I've absolutely fallen in love with Typescript. Not only is it backed by Microsoft, but its integration with VSCode (through Intellisense and TSLint) has been great. It really allows you to write code you can trust by ensuring values in, out and across, are correct and properly formed.

From a pure web-perspective... a good Typescript setup with Babel/Browserify and some polyfills, can allow you to write modern Javascript that transpiles down to something that's able to work even on older browsers. Keeping a nice, clean, modern source code.

I currently have a large Typescript library assisting an enterprise company processing over 15 million hits a month successfully.

Blog

Not much to say here, but I moved away from Jekyll and moved to Ghost, simply to have a nice interface for writing posts and something I could further customize.

I also opted to develop a modified theme which had colors that were pleasing to the eyes, and easily readable. I based my colors on my favourite editor theme, from RainGlow called UserScape (High Contrast).

Its still powered by Github Pages through a custom script I have which uses Buster to turn my Ghost installation locally into a pure HTML website, which gets uploaded directly to Github.

Digital Fingerprint

Essentially this involved de-Googling as much as I could. Google used to be a great company to my eyes - creating leading-edge software with first-class Android integration.

But the last couple years, they've turned into a pile of shit. No other way to put it. Discontinuing many services and apps and creating a bunch of useless ones, not only showing instability or trust in investing into their ecosystem, but it shows lack of direction. This, on top of their constant privacy issues has driven me away.

It took quite a bit of time to move away from what I could move away from...

Email & Browsing

I've opted to go full-time with Firefox and Thunderbird on the desktop to manage my browsing and e-mail/calendar access. Both solutions are highly customizable, community-backed, and open source. Firefox also has great Android apps such as Firefox itself and Firefox Focus.

I've also moved away from Gmail and the whole Gsuite of products. Gmail itself plain sucks.... from its obscure standards (such as labels and own "IMAP" implementation), to its ever-changing feature-set, it became a disaster and forced you to stick with their product (Google's goal anyways...).

I have moved on to private services such as MailBox.org which gives you a full e-mail/calendar/contact setup for $15 a year.

Services like MailBox.org, PrivateEmail.com, FastMail.com, are all great because they're well... private! Also secure and are based on existing standards such as CalDav, CardDav, and IMAP, allowing you to easily use many popular software on the desktop and mobile to access your digital content (by the way, Android doesn't support *Dav out of the box... I guess another way for Google to keep you locked in).

Drive

This one was hard. It took me months to find a suitable service. I have a lot of documents which Google (creepily) scans via OCR allowing it to be very searchable. They also offered a nice chunk of free space, 15GB last I used it.

I researched and tried many... from Dropbox, which disappointed in price and syncing abilities to a strong second place runner-up of Sync.com, which I liked, but didn't provide Linux integration.

I settled on pCloud, which has a great set of security features, flawless syncing across all my devices, including Linux, and a great web interface. It also has a hard to beat pricing system, allowing you to pay a one-time life-time fee for their service, or a low monthly cost. It also comes with 10GB (unlockable) space for free to try out as long as you like.

The only feature I miss so far is the OCR that Drive provided, but I'll manage without it for now.

Document Suite

I've moved to use LibreOffice on the desktop, which has given me no issues editing any type of document so far, even Doc and Excel files.

For mobile, I've wen't with Polaris Office for Android. I have not used it much as I do not normally edit docs on-the-go, but the few times I did, it managed the job fine.

Other Services

I've yet to break off from anything else. Some people have had success moving away from Google Maps and Youtube, but its not my direct interest right now. Currently I am happy having my core information moved away!


In the end, I've been move productive than I thought originally. I've accomplished a lot, changed a lot, and hope to continue growing. Cheers!

]]>
<![CDATA[Thunderbird with GSuite & Exchange]]>Its true desktop clients are on the decline in favour of easily accessible web clients (such as GMail, Outlook.com). However, if you've ever used a complete native desktop client before such as the star of it all, Outlook, then you know nothing on the web can come close.

Besides

]]>
https://ohmybrew.com/thunderbird-with-gsuite-exchange/5c34feecd6c9242dfe62ac2aTue, 08 Jan 2019 20:20:24 GMTIts true desktop clients are on the decline in favour of easily accessible web clients (such as GMail, Outlook.com). However, if you've ever used a complete native desktop client before such as the star of it all, Outlook, then you know nothing on the web can come close.

Besides the obvious dependability/extendability of endless settings you can tailor to your liking, desktop clients come with the added benefit of offline and powerful instant search. If you travel occasionally like myself, doing work while up in the air is much easier when you have your entire mailbox, address book, and schedule in front of you.

Why Thunderbird

Well, I'm on Linux to start, but its also a great well-tested application suite backed by Mozilla. It features a large helpful community, a wealth of addons, and its open source. I considered using Evolution but it didn't quite meet to my standards of needs.  Other clients such as the popular Geary, are simply too basic to work with when you're dealing with business activities.

Setup for GSuite

Mail

Google implements their own standards when it comes to a lot of things, IMAP is one of them. Instead of folders, Google chose to implement "labels" which translates poorly on my clients.

Luckily Thunderbird handles this well. Simply add your Google account to Thunderbird as normal and configure the account settings to your liking.

Calendar

You'll need two addons for this to work.

  1. "Ligtning" - The integrated calendar & scheduling addon for Thunderbird
  2. "Provider for Google Calendar" - Allows bidirectional access to Google Calendar.

Once both are installed, simply click the menu icon for Thunderbird > "New Message >" > Calendar.., to open the calendar dialog. From here, select "From network...", then "Google Calendar". You should now be able to enter your Google account information and your calendars will sync.

Contacts

For contacts, you'll need to install "gContactSync". Once installed, click the menu icon for Thunderbird, go to Addons > gContactSync. Enter your Google account information, choose the lists you wish to sync, and hit save.

This addon does support contact photos as well.

Setup for Exchange / Outlook

Mail

Thunderbird supports this out of the box, if your using Outlook.com you may need to generate an app password for your account to connect. Enter your account information and your mail will begin to sync.

Calendar & Contacts

For this to work, you'll need the following addons:

  1. "TbSync" - Sync contacts, tasks, and calendars for Exchange
  2. "Provider for Exchange" - Adds sync support for Exchange accounts for TbSync
  3. "Ligtning" - The integrated calendar & scheduling addon for Thunderbird

Once installed, click the menu icon for Thunderbird, go to Addons > TbSync > Account Actions > Add a new account. Enter your account information and a dialog will appear allowing you to select which contact lists to sync and which calendars to sync. Once chosen, click "Synchronize this account".

Done! Now your contacts and calendars will appear once syncing is complete.

One note, the contact images do not seem to work though (for me)...

Screenshots or it didn't happen!

Fine!

Example of GSuite & Exchange Mail + Events List
Address book with GSuite & Exchange
]]>
<![CDATA[Thinkpad T580 on Linux]]>Lenovo is known for creating configurable machines that are great for both business and consumers, which are easily extendable or fixable by the average user thanks to their documentation and sane build.

They're also one of the very few vendors, if not the only, to claim Linux compatibility ("out of

]]>
https://ohmybrew.com/thinkpad-t580-on-linux/5c34f408d6c9242dfe62abb6Tue, 08 Jan 2019 19:44:11 GMTLenovo is known for creating configurable machines that are great for both business and consumers, which are easily extendable or fixable by the average user thanks to their documentation and sane build.

They're also one of the very few vendors, if not the only, to claim Linux compatibility ("out of the box" working) for many models.

My Machine

  • Lenovo ThinkPad T580 (2018)
  • 32GB RAM
  • 500GB SSD
  • 15.6" UHD matte screen
  • Intel i7-8650U CPU @ 1.90GHZ x 8
  • Intel UHD 620 (Kabylake) / Nvidia MX150
  • Fingerprint reader
  • Lenovo USB-C Dock

Distro Choice

History

I've been around the block when it comes to Linux, used it for over a decade, with 2003 being my first self installation experience. It was a tough experience at that, head diving into non-GUI command line installations, partitioning, and many pages of installation manuals to read over.

I've tried everything from FreeBSD, Debian, Fedora, DSL, Redhat, OpenSUSE, Gentoo, Ubuntu, Slackware, Mandriva, Arch, and more. Hell, I even tried out Linux from Scratch for fun!

All that distro-hopping gained me a lot of experience, and by experience I mean the type of experience you gain when your system crashes for some random reason, becomes unusable, random annoyances you have/want to solve. Many of these distros I stuck with and used for years happily.

However, the last few years (if you can tell from my posts), I've been in the land of Mac and Windows... simply because at the time, I needed things to "just work" and being as mobile as I was, I couldn't afford my machine failing on me during a presentation or on-site job. I didn't even trust the ol' Debian route out of that fear.

Change

Not to knock Mac or Windows, they're fine systems and you can get the job done on both through many of the tools available these days such as Vagrant, Docker, or even Microsoft's new WSL; but it just doesn't feel like home. You don't feel the control or the fullness open source software can bring you.

With my new T580, I decided to change that and get back on Linux - bite the bullet and make the system work but also trustworthy.

Thought a lot of research, trial and error, I ended up choosing Pop!_OS. Its a distro based upon Ubuntu with many patches to assist in things like multi-DPI, Intel/Nvidia graphics switching, custom beautiful theming/icons, and sane defaults. Its the distro they pack into their own System76 machines.

Installation

Installation was pretty simple, Pop's installer is well made, easy to follow and clean.

Before beginning installation, I did the following:

  • Wrote Pop to a USB stick
  • Disabled Secure Boot in the BIOs
  • Disabled Window's paging
  • Disabled Window's restore point
  • Shrunk Windows partition (through Windows Disk Management) to bare minimum

Next:

  • Created a EXT4 partition from the unallocated space
  • Set Pop to use the new partition for the boot
  • Set Pop to use the existing EFI partition

Pop then installed the system successfully and created a default boot entry.

Everything upon boot worked. Screens, WIFI, Bluetooth, etc.

Tweaks

To make the most out of the ThinkPads, you should install the following.

TLP

TLP is a power saving utility with special additions for Thinkpads. Such as battery thresholds, statistics, charging plans, recalibration and more.

sudo apt install tlp

With this, you should also install the kernel modules for thresholds to work.

sudo apt install tp-smapi-dms

sudo modprobe tp-smapi

For more information visit the TLP webpage.

Audio

With the newer ThinkPads, Lenovo ships them with Dolby Digital assistant for Windows to really make the built-in speakers sound beefy. On Pop (any others), the speaker will sound average... even lame.

To help with this, we can install PulseEffects. This is a complete tool for managing the audio output, allowing you to adjust and save/load presets to your liking.

sudo apt install pulseeffects

Once installed I recommend you check out this repository on Github for some great ready-made presets. I personally recommend Perfect EQ.

Now, your speakers, and even other audio devices will sound great!

Wayland

If you have an Intel graphics card like me, then you're able to use Wayland.

sudo nano /etc/gdm3/custom.conf

Find WaylandEnable=false and commend it out: #WaylandEndable=false. Then, sudo systemctl restart gdm.service.

You should now be logged out and a visible cog icon should show next to "Login". Click it and select "Pop (Wayland)".

The only downfall is Firefox (and Chrome), as well as Thunderbird, do not support the scaling properly yet. I've heard the nightly edition of Firefox does solve these issues however.

Given those scaling issues, I personally remain on the default Xorg for now. Which is totally fine! Pop has a great daemon running to detect when you plug in mixed DPI screens to the laptop. It will automatically adjust the resolutions to match so you won't have scaling issues.

Nvidia

As of writing, you can install the nvidia-410 driver which works fine for the MX150.

Running sudo powertop and switching to the tunables tab, you should see a "BAD" status for the Nvidia power management. Simply click enter, to check it from bad to good. Using the recommended changes, my power usage for Nvidia (7-9W) closely matches Intel (6-8W of usage).

A Month Later

Its now been a month and I've experience no issues besides the rare issue of the desktop freezing sometimes when I plug in my USB-C dock.

Overall, Pop is a great polished distro with a lot of care put into its end-to-end process from installation to the end-user experience with the polished custom themeing. Give it a try!

]]>
<![CDATA[Apply, Verify, and Validate Shopify Discount Codes]]>Shopify doesn't have an API to verify discount, however I have found a little work-around.

By making an AJAX call to /discount/(code), Shopify will set a cookie telling the checkout to auto-apply a discount on visit to the checkout page.

Next, making an AJAX call to /checkout, we're able

]]>
https://ohmybrew.com/apply-verify-and-validate-shopify-discount-codes/5bc93b19b15546125023bdfbFri, 19 Oct 2018 02:14:59 GMTShopify doesn't have an API to verify discount, however I have found a little work-around.

By making an AJAX call to /discount/(code), Shopify will set a cookie telling the checkout to auto-apply a discount on visit to the checkout page.

Next, making an AJAX call to /checkout, we're able to parse the HTML and determine if the discount code worked!

Here's an example of it in action:

promo-verify

For source code of this script, please see this repository.

]]>
<![CDATA[Moved to Ghost]]>

Background

I originally created my blog with Jekyll for the past few years. Jekyll is an amazing static-site generator created with Ruby; it gives you full control over the templates, markdown, and more.

However, I recently found Ghost. Ghost is a paid publishing platform which also offers their platform as

]]>
https://ohmybrew.com/moved-to-ghost/5a8dbdff3f9db9150b632d47Wed, 21 Feb 2018 19:10:45 GMT

Background

Moved to Ghost

I originally created my blog with Jekyll for the past few years. Jekyll is an amazing static-site generator created with Ruby; it gives you full control over the templates, markdown, and more.

However, I recently found Ghost. Ghost is a paid publishing platform which also offers their platform as open-source on Github.

What I like about Ghost is it's beautiful administration panel that lets me just focus on writing (in Markdown). It comes with a lot of features and plugins; like integration with Unsplash, featured image support, basic Markdown tools, meta modifications, excerpts, spell checking, tag tracking, live previews, etc.

I took the plunge and decided to move.

Moving

First, I wrote a quick script to convert the Markdown files into a Ghost-compatible JSON file for import.

Essentially taking the YAML frontmatter that Jekyll uses, moving it into a JSON file, and uploading it into Ghost's administration panel.

For images, I simply dropped them right into the content/images of the Ghost installation.

Static Generation

So one problem, Ghost is writtin in NodeJS and is meant to be run on a server. It is not a static generator like Jekyll.

Using a tools, like Buster, we can overcome this problem fairly easy.

Buster

You can install Buster; a simple static-generator for Ghost which crawls the Ghost installation using wget and produces a static structure ready to upload to Github pages or other static hosting providers.

Its a simple as using your terminal to move into the Ghost installation, and typing pip install buster, followed by buster setup.

Buster Clean-Up

Buster produces raw files... no fixing for domain names, HTTPs, and all files and anchor tags are preserved to use ".html" at the end.

I modified a script from StefanScherer/ghost-buster-docker to fix the domain names, move all http to https, clean up .html from links, and more. You can view the Gist here.

Save it to your Ghost installation was buster.sh and be sure to give the file the correct permissions to run. Also, change my domain name for your domain name.

Next, create a folder inside your Ghost installation:
mkdir static; mkdir copy

  • static is where Buster will generate the files.
  • copy is where you wish to place files to be copied over after Buster has ran (README.md, CNAME, etc).

Now, start Ghost up with npm start. Once started, run ./buster.sh --deploy.

The script will clear out the static folder, run the static generation, fix all the links within the HTML and sitemaps, clean up any cruft, copy the files over from copy, and push the result to Github.

Thats it! Ghost > Static Generation > Github Pages. I'm really enjoying Ghost thus far, and I hope you too will check it out.


Cover image credit: Toa Heftiba

]]>
<![CDATA[Laravel Shopify Billing]]>

Version 2.0.0 was just released which features the baked-in ability to turn your Shopify app into a billable app with some simple configuration additions.

It has support for the two methods Shopify supports, single and recurring charges. You have the ability to set the plan name, price, trial

]]>
https://ohmybrew.com/laravel-shopify-billing/5a8ca2fd415b127824f260edFri, 26 Jan 2018 15:52:56 GMTLaravel Shopify Billing

Version 2.0.0 was just released which features the baked-in ability to turn your Shopify app into a billable app with some simple configuration additions.

It has support for the two methods Shopify supports, single and recurring charges. You have the ability to set the plan name, price, trial days, and more.

You also have to ability to easily upgrade or downgrade a shop's plan, enable them as a grandfather (skip billing), and more.

For full information see the release notes, upgrading doc, and the wiki page for creating a billable app.

Other minor updates include integration with StyleCI to keep coding standards within PSR1 and PSR2.

]]>
<![CDATA[Setting Up Lumen + Redis]]>

This is more of an extension of my previous post "Setting Up Lumen + Mail". I wanted to take it a step furthur and show the basic setup for getting Redis to work, so you can queue not only mail, but jobs.

First, run composer require illuminate/redis:5.

]]>
https://ohmybrew.com/setting-up-lumen-and-redis/5a8ca2fd415b127824f260e8Sun, 19 Nov 2017 11:43:01 GMTSetting Up Lumen + Redis

This is more of an extension of my previous post "Setting Up Lumen + Mail". I wanted to take it a step furthur and show the basic setup for getting Redis to work, so you can queue not only mail, but jobs.

First, run composer require illuminate/redis:5.5 to grab the Redis components.

Next, open app/Providers/AppServiceProvider.php and add the following to the register method:

<?php
// ...

// Configs
$this->app->configure('database');

// Enable queues
$this->app->make('queue');

Next, create config/database.php and add the following:

<?php

return [
  'redis' => [
    'client' => 'predis',
    'default' => [
      'host' => env('REDIS_HOST', '127.0.0.1'),
      'password' => env('REDIS_PASSWORD', null),
      'port' => env('REDIS_PORT', 6379),
      'database' => 0
    ]
  ]
];

Don't forget to setup all your environment variables for Redis, as well, to enable Redis for job processing and cache, set the following environment variables:

CACHE_DRIVER=redis
QUEUE_DRIVER=redis

That's it! You can now queue mail or process jobs.


Cover image credit: Jingyi Wang

]]>
<![CDATA[Setting Up Lumen + Mailer]]>

What is Lumen?

Lumen is a micro-framework built by Laravel. Its geared towards small services like APIs, job handling, or very small projects. Laravel is all-inclusive, where as Lumen is bare-bones but still featured.

Setting Up Mailing

Recently I ported a small app from Sinatra to Lumen for trial with

]]>
https://ohmybrew.com/setting-up-lumen-and-mail/5a8ca2fd415b127824f260e1Sun, 19 Nov 2017 11:04:33 GMT

What is Lumen?

Setting Up Lumen + Mailer

Lumen is a micro-framework built by Laravel. Its geared towards small services like APIs, job handling, or very small projects. Laravel is all-inclusive, where as Lumen is bare-bones but still featured.

Setting Up Mailing

Recently I ported a small app from Sinatra to Lumen for trial with a client. Its a job processing app for Shopify, where it would take data from a web hook, process it with a worker, and send back some data later. It needed to be fast, as like other webhook-focused app, it has to keep up with the high demand.

One issue I ran into was mailing, its not enabled by default in Lumen, and there are many posts throughout Google of people attempting to set it up. There is also many outdated ways which only worked for old version of Lumen.

Through trial and error, I managed to find a working setup I thought I would share.

Setup

First, run composer require illuminate/mail:5.5 to grab the mailing component.

Next, open bootstrap/app.php, find $app->register(App\Providers\AppServiceProvider::class); and uncomment it, if not already.

After this is done, open the app provider in app/Providers/.

At the bottom of the register method, paste in the following:

<?php
// ...

// Init mailer
$this->app->singleton(
    'mailer',
    function ($app) {
        return $app->loadComponent('mail', 'Illuminate\Mail\MailServiceProvider', 'mailer');
    }
);

// Aliases
$this->app->alias('mailer', \Illuminate\Contracts\Mail\Mailer::class);

To make mailing queue-able and able to be processed in the background, simply add:

<?php
// ...

// Enable queues
$this->app->make('queue');  

And see my Lumen Redis tutorial to setup Redis for processing.

Next, setup the basic config config/mail.php:

<?php

return [
    'driver' => env('MAIL_DRIVER'),
    'host' => env('MAIL_HOST'),
    'port' => env('MAIL_PORT'),
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS'),
        'name' => env('MAIL_FROM_NAME'),
    ],
    'encryption' => env('MAIL_ENCRYPTION'),
    'username' => env('MAIL_USERNAME'),
    'password' => env('MAIL_PASSWORD'),
    'markdown' => [
        'theme' => 'default',
        'paths' => [
            resource_path('views/vendor/mail'),
        ],
    ],
];

That's it, you're done the setup! Don't forget to setup your environment variables for production.

Creating a Mailer

Now that we're setup, you can create a mailer in app/Mail/, heres an example to go by (app/Mail/Winnings):

<?php namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class Winnings extends Mailable
{
    use Queueable, SerializesModels;

    /** @var string the address to send the email */
    protected $to_address;

    /** @var float the winnings they won */
    protected $winnings;

    /**
     * Create a new message instance.
     *
     * @param string $to_address the address to send the email
     * @param float $winnings   the winnings they won
     * 
     * @return void
     */
    public function __construct($to_address, $winnings)
    {
        $this->to_address = $to_address;
        $this->winnings = $winnings;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this
            ->to($this->to_address)
            ->subject('Your winnings!')
            ->view('emails.winnings')
            ->with(
                [
                    'winnings' => $this->winnings
                ]
            );
    }
}

Now, create a view, resources/views/emails/winnings.blade.php for simply HTML-only,:

{% raw %}<strong>You won {{ $winnings }}</strong>!{% endraw %}

Sending Mail

Now that we have it setup, and a mailable created, we can send. In your job, controller, or where ever you need it:

<?php
use App\Mail\Winnings as WinningsMail;

// ...
// $to_email = 'john@doe.com'; $winnings = 130.00;

Mail::send(
    new WinningsMail(
        $to_email,
        $winnings
    )
);

If you're queuing mail, replace send with queue. You can also see Laravel's mail documentation for more information on sending.

Testing

Of course, we need to test (tests/WinningsMailTest.php):

<?php

use App\Mail\Winnings;
use Illuminate\Support\Facades\Mail;

class WinningsMailTest extends TestCase
{
    public function testItWorks()
    {
        Mail::fake();

        Mail::send(
            (new Winnings('john@doe.com', 15.00))->build()
        );

        Mail::assertSent(Winnings::class, function ($mail) {
            return $mail->hasTo('john@doe.com') &&
                   $mail->subject === 'Your winnings!' &&
                   $mail->viewData['winnings'] === 15.00;
        });
    }
}

Running the tests should pass if everything is setup correctly. For more information on testing mailables, see Laravel's documentation on faking.

I hope this was a quick and useful setup for anyone having issues. Good luck!


Cover image credit: Mikael Kristenson

]]>
<![CDATA[Pomodoro Method]]>

I've had a history of a bad back and neck, ever since I was a kid. I've seen a chiropractor countless times about my issues. Sitting all day at a desk in my adult years, doesn't help at all to that.

Researching in help for this, besides ergonomics of the

]]>
https://ohmybrew.com/pomodoro-method/5a8ca2fd415b127824f260fcFri, 20 Oct 2017 14:00:00 GMTPomodoro Method

I've had a history of a bad back and neck, ever since I was a kid. I've seen a chiropractor countless times about my issues. Sitting all day at a desk in my adult years, doesn't help at all to that.

Researching in help for this, besides ergonomics of the workstation, I stumbled upon the Pomodoro method. A small addition to the day, but a big pay off in my health.

What is a Pomodoro Clock?

The idea is about sectioning work into timed intervals, typically 25 minutes. After completing an interval of work, you take a 5 minute break. After 4 intervals of work, you take a longer, 15-30 minute break.

Benefits

Your brain needs a break, but also your body. As a programmer, you're desk locked most of the time. You need time to decompress, stretch, and realign yourself from time to time.

Sticking to the Pomodoro method, you'll get in a rhythm of doing your work, then having your break, allowing you to get up out of your desk. This can prevent back issues, neck issues, soreness, and burnouts.

Pomodoro & Programming

Programmers hate interruptions. A major interruption to a programmer can on-average, take 10-15 minutes to "recover" back into the mindset of the task at hand.

The thing about programming is you're mentally managing connections between systems, files, methods, etc. An interruption can sever those connections instantly and require you to rebuild it before starting work.

Its as if you had 5 books open on a table and you're reading different paragraphs in each book which all relate. You're in the zone connecting all these similar paragraphs of information for research... when suddenly - someone asks you where you bought your backpack. Oops, there goes your train of thought, and you'll sit there looking at those 5 books and no longer have an idea of where you we're.

Its hard to turn tasks of programming work into sections of 25 minutes due to this. When the timer is up, you're supposed to take a 5 minute break, but if you're deep into a task, it could seem like an interruption and distraction. Its really hard.

Overcoming & Adapting

I was skeptical the method would work for me, the thought of stopping when the timer is done just kept a message playing in my head, "this is a bad idea, this is a bad idea," because I felt this would cause me to lose track of what I was doing and actually hinder my day, not improve it.

But, due to my past and current back/neck issues, I decided to give it a go - rip the bandaid off.

The first few days was hard. Several times the timer would go off and I would say, "one more minute I'll be good," "one more minute, I'll have the task done," and guess what... it was never a minute. I got into that deep vibe and before I knew it, hours past and I was sore and my eyes we're tired.

I realized this and decided I have to be more proactive on it. Adapt.

When that timer would go off, I'd take a mental note of my current status and just drop it all, stand up, and walk around... get a coffee... decompress for 5 minutes.

Yes, coming back to the work after the break, it took a few minutes to realign, which was frustrating at first, but I knew it was worth it for my health.

Over time (currently a month doing this), realigning surprisingly got easier and easier, I somehow trained myself better coming back to a task.

Results

Its amazing. 5 minute breaks after every task seems small. But the posture of my body, pain, soreness, and mental state, have all been improved by doing these little breaks and timed workloads.

I have time to stand up, walk, stretch, and let my eyes adjust to something besides a glaring LCD panel.

Its a hard adjustment but just try it, commit to it, and try it for a week. It helped me.

Tools

There's phone apps, web apps, desktop apps. You can even buy a physical timer to slap on your desk. Some are bare, some are rich in features.

Personally, I just needed a timer for the work (25 minutes), break (5 minutes), and a long break (15-30 minutes). An addon for my Firefox fit the bill perfect, called Tomoto Clock which is under active development. It supports the 3 types of timers, with a visual/sound notification, it also keeps stats of your daily usage for tasks and breaks. Its super simple to use.


Cover image credit: Vince Lee

]]>
<![CDATA[Introducing Laravel Shopify]]>

Background

As an active Ruby (and Rails) developer, I found myself regularly making Shopify apps in Rails and Sinatra. I've even released my own Gems to solve common (small) issues I've faced developing for these platforms.

PHP itself... I haven't been active in years on that front. With PHP7 however,

]]>
https://ohmybrew.com/introducing-shopify-for-laravel/5a8ca2fd415b127824f260e3Wed, 09 Aug 2017 16:35:00 GMT

Background

Introducing Laravel Shopify

As an active Ruby (and Rails) developer, I found myself regularly making Shopify apps in Rails and Sinatra. I've even released my own Gems to solve common (small) issues I've faced developing for these platforms.

PHP itself... I haven't been active in years on that front. With PHP7 however, the language is shaping up. It doesn't have the great method chaining or syntax beauty that Ruby does, but its a well tested, proven, and mature language to work with that's easily deployable to a magnitude of places without much interaction.

Being out of the PHP game for a while, I decided to survey the landscape. I used to work heavily with Symfony, however it always left a sour taste in my mouth. Symfony is great... its really well structured, enterprise type of framework. It falls short for medium-sized projects due to the verbosity of it (in my personal experience).

After some digging, I stumbled upon Laravel. Laravel, like many projects, uses bits of Symfony's core and builds on top of it. I spent a lot of time studying Laravel, its community, its activeness, its code. It looked solid and had great tools and documentation to go along with it. It has a lot baked into it, which is all easily configurable and accessible - it felt like Rails for PHP honestly.

shopify_app is Shopify's own gem for building Shopify apps on Rails; quick and easy. It handles authentication, installation, webhooks, scripttags, ESDK integration and more. In Laravel, I could not find a package which covered all those points. I decided I'd go head first into Laravel and build a package for it.

What The Package Does

Right from the Github page, the package handles all that shopify_app does:

  • Provide assistance in developing Shopify apps with Laravel
  • Integration with Shopify API
  • Authentication & installation for shops
  • Auto install app webhooks and scripttags thorugh background jobs
  • Provide basic ESDK views
  • Handles and processes incoming webhooks
  • Handles and verifies incoming app proxy requests

The package is fully tested and works with PHP >= 7 and Laravel 5.4.

Project

You can head over to the project's page for full information, or also browse the wiki for documentation, installation, and other topics.

Happy coding with Shopify + Laravel!

]]>
<![CDATA[Reactive VueJS Plugins]]>

VueJS has been my go-to framework from building small to medium-sized frontend applications and add-ins. Its simply great - easy to develop with and able to plug into existing systems as a simple view layer.

Plugins & Reactivity

Plugins in Vue, allow you to extract code into a re-usable module.

]]>
https://ohmybrew.com/reactive-vuejs-plugins/5a8ca2fd415b127824f260f3Thu, 29 Jun 2017 12:36:22 GMT

VueJS has been my go-to framework from building small to medium-sized frontend applications and add-ins. Its simply great - easy to develop with and able to plug into existing systems as a simple view layer.

Plugins & Reactivity

Plugins in Vue, allow you to extract code into a re-usable module. The plugins allow you to create global mixins, methods, properties, and more. It has the added benefit of keeping your code modularized, clean, and doesn't pollute your app's main instance.

Reactivity in Vue is simply a way of describing something that watches for changes in state/data and reacts to it. Vue watches for changes in data, which in turn causes the component to re-render, showing the updated state.

Use Case

As mentioned, creating plugins can keep your code modularized and your main app instance clean. There could be many reasons you'd need a plugin to track data (be reactive).

One example is if you're depending on a third-party service for data. You need to request this data, process it, save it, and display it. This takes time. By the time the request is completed your Vue instance may be rendered and your data will not display.

Building

Lets build a sports ticker to show the latest score result from some sports team.

The key to making your data reactive in your plugin is simple... create a new Vue instance which holds the data.

// plugins/sports-ticker.js

/**
 * Simple sports ticker class
 */
class SportsTicker {
  /**
   * @constructor
   */
  constructor(Vue, team) {
    this.team = team;

    // Lets make a new instance to store the data
    this.storeVM = new Vue({
      data() {
        return {
          team,
          gameTime: null,
          score: {
            home: null,
            away: null,
          },
        };
      },
    });
    
    // Fetch the scores
    this.fetchData();
  }

  /**
   * Gets the state of the data
   * @return {Object}
   */
  get state() {
    return this.storeVM.$data;
  }
  
  /**
   * Simple fetch to grab the data
   */
  fetchData() {
    fetch(`https://some-api.com/games/${this.team}/last`)
    	.then(resp => resp.json())
    	.then((data) => {
    		this.state.gameTime = data.game_time;
    		this.state.score = {
    			home: data.home_score,
     			away: data.away_score
    		};
   		})
    ;
  }
}

export default {
  /**
   * Install sports ticker plugin
   * @param {Vue} Vue - Vue instance
   * @param {Object} options - Options for the plugin
   */
  install: (Vue, options = {}) => {
    Vue.prototype.$SportsTicker = new SportsTicker(
      Vue,
      options.team
    );
  },
};

// Usage: import SportsTicker from 'plugins/sports-ticket'; Vue.use(SportsTicker);

That's all that's to it.

What we've done is created a class to keep our logic separate from the Vue plugin installation code. Then, we register the plugin with the options (in this case, just team name). In the SportsTicker class, we create a new Vue instance with its own data store filled with dummy/default data. We create a get state method so we can quickly access the data of the Vue instance we created. Next, we fetch the data, process it, and write it back to our Vue instance.

With all this in play, our data is now reactive.

<template v-if="$SportsTicker.state.gameTime">
  {% raw %}
  {{ $SportsTicker.state.team }}'s last game results: {{ $SportsTicker.state.score.home }} - {{ $SportsTicker.state.score.away }}
  {% endraw %}
</template>

Because the data is reactive, the above view snippet will not show until we have data (checking gameTime is not null in this case). When the data is processed, it will trigger Vue to render the template and show the data.

All we needed to do was create our own Vue instance for the plugin to store the data, with a simple method to access it (get state).

]]>