Compare
aaa37b5be825bcbaa2ab68b02bc4775838289859
…
main
· 62 commits
Commits
@@ -10,7 +10,7 @@ unsafe=true
[params]
author = "Ryan Schanzenbacher"
-info = "Second Year Computing Security Student"
+info = "Cybersecurity Engineer"
keywords = "blog,personal"
description = "Ryan Schanzenbacher's Personal website"
hideCredits = true
@@ -18,6 +18,11 @@ colorScheme = "dark"
hideColorSchemeToggle = true
#avatarURL = "/imgs/profile/avatar.png"
+[[params.social]]
+ name = "Git"
+ icon = "fa fa-git-square fa-2x"
+ weight = 0
+ url = "https://git.rschanz.org"
[[params.social]]
name = "Github"
icon = "fa fa-github fa-2x"
@@ -31,29 +36,27 @@ hideColorSchemeToggle = true
[[params.social]]
name = "Email"
weight = 3
- url = "mailto:rjs1877@rit.edu"
+ url = "mailto:inquiries@rschanz.org"
icon = "fa fa-envelope fa-2x"
[[params.social]]
name = "Resume"
- weight = 4
+ weight = 7
icon = "fa fa-file-text-o fa-2x"
url = "/resume/Schanzenbacher_Ryan_Resume.pdf"
[[params.social]]
name = "GPG Key"
- weight = 5
+ weight = 4
icon = "fa fa-key-modern fa-2x"
url = "gpgkey.asc"
-#[[menu.main]]
-# name = "About"
-# weight = 1
-# url = "/about"
-
+[[menu.main]]
+ name = "Presentations"
+ weight = 3
+ url = "https://p.rscha.nz"
[[menu.main]]
name = "Projects"
weight = 2
url = "/projects"
-
[[menu.main]]
name = "About"
weight = 1
@@ -6,7 +6,7 @@ draft: false
## Hi! :wave: My name is Ryan!
-Hello, and welcome to my site! My name is Ryan Schanzenbacher. I'm currently a second-year student at the Rochester Institute of Technology studying Computing Security, expecting to graduate in 2024. Now since that's out of the way, a little about me. I've always had a passion for computers from a young age. For as long as I can remember, I've been fascinated by both how they work and how to use them to their fullest potential. Another starting point for my interest in computers was whenever my Dad and I sat down to try and fix a computer. His job required him to fix computers more often than not, and sometimes I would be able to show up at his workplace and just watch what he was doing. Or, another time was when he had an older laptop that we worked togethor on to try and get Windows 98(!) to run on again. Those types of events helped shape my interests into what they are today.
+Hello, and welcome to my site! My name is Ryan Schanzenbacher. I'm currently a Cybersecurity Engineer working in NYC. Now since that's out of the way, a little about me. I've always had a passion for computers from a young age. For as long as I can remember, I've been fascinated by both how they work and how to use them to their fullest potential. Another starting point for my interest in computers was whenever my Dad and I sat down to try and fix a computer. His job required him to fix computers more often than not, and sometimes I would be able to show up at his workplace and just watch what he was doing. Or, another time was when he had an older laptop that we worked together on to try and get Windows 98(!) to run on again. Those types of events helped shape my interests into what they are today.
### Another starting point
@@ -29,5 +29,5 @@ Now, after some amount of time, I decided to remove the WUBI install because it
### Taking the plunge
-So I used this setup for some time, probably until like mid-2011 or so. I kept using both OSes, though my Windows XP install was just taking up space for not a lot of use. I couldn't really do too much on it anymore, so I eventually decided to just take the plunge. I put everything I needed on on a USB drive, and just reinstalled everything on the PC, this time choosing "Use this entire drive for Ubuntu." Goodbye Windows! I realize I probably didn't need to reformat my entire computer to do this, but at the time this is how I knew to do it. Ever since then, I don't think I've had a permanent Windows install on a computer. I've fallen in love with Ubuntu and the ideals surrounding it. Fast-forward to today, I distro-hopped more times than I can count on my hands; all for various reasons. One may have been I preferred the DE of another distro, or Ubuntu didn't have the package I wanted, etc.
-So I probably used Ubuntu, Kubuntu, Xubuntu, Fedora, Puppy Linux, OpenSUSE, and Arch in my lifetime. At the moment, I use Arch on most of my systems, since I can choose pretty much exactly what I want to install.
+So I used this setup for some time, probably until like mid-2013 or so. I kept using both OSes, though my Windows XP install was just taking up space for not a lot of use. I couldn't really do too much on it anymore, so I eventually decided to just take the plunge. I put everything I needed on on a USB drive, and just reinstalled everything on the PC, this time choosing "Use this entire drive for Ubuntu." Goodbye Windows! I realize I probably didn't need to reformat my entire computer to do this, but at the time this is how I knew to do it. Ever since then, I don't think I've had a permanent Windows install on a computer. I've fallen in love with Ubuntu and the ideals surrounding it. Fast-forward to today, I distro-hopped more times than I can count on my hands; all for various reasons. One reason may have been I preferred the DE of another distro, or maybe Ubuntu didn't have the package I wanted, etc.
+so I probably have used Ubuntu, Kubuntu, Xubuntu, Fedora, Puppy Linux, OpenSUSE, and Arch in my lifetime. At the moment, I use Alpine on my servers and Guix as my daily-driver distribution on my personal computers.
@@ -1,25 +0,0 @@
-title: "Home Media Server"
-date: 2022-01-10T08:50:50-05:00
-draft: true
-
-## Some History
-
-Now that I am coming off of my winter break, I'll finally have a chance to write about some of the things I was able to do over it. So, this post will be the first in a series of two detailing two big projects I worked on over the past 4 weeks. First, I'd like to talk about the bigger of the two projects: Rennovating my home media server. Around the summer of 2018, my Dad and I started to undertake the process of digitizing all of our media. Now, legal gray area aside, this was a success, and after almost a year of work we finally had most things digitized. Now, the goal was to eventually make everything available to the entire house. We weren't sure how to go about this, but I've heard of an application named "Kodi", so I installed a distribution of Ubuntu onto a spare computer named "Kodibuntu." This was easy enough to set up, and soon enough we had all of our songs and most of our movies stored on this machine, ready to be viewed at a moments notice.
-
-About 6 months after this was set up, and numerous crashes from Kodi, I started looking for a different solution. I was very passive in my search, I had schoolwork to focus on as well, so this project sort of hit the backburner for a while. However, one day I was scrolling through my Google Feed and saw a github page for a project named "Jellyfin" claiming to be useful for media servers. I took a look at the project and it filled all of our boxes! Self-hosted, auto indexing software for all of our media, all while providing a central interface to get everything from. So, one weekend I tore out Kodi and replaced it with Jellyfin; after all Kodibuntu was just Ubuntu with Kodi on top of it, so I had access to all of the Ubuntu Repos. After that, it just sat there, slowly collecting any new media we got, waiting for us to watch stuff from it (which we do all the time, we have an Android TV with the Jellyfin app, we watch things on there all the time!).
-
-## A Growing Problem
-
-Around mid-2020, our USB DVD reader died while ripping a DVD. This was unfortunate, but it was going on 3 years old at this point, it was probably its time. So, we decided it was time to upgrade. We ended up buying a USB Bluray drive so we could begin to rip HD and UHD content to our media server; I mean, the TV we had downstairs was a UHD TV, it was time to stop watching 480p DVDs on it. We had a 1TB drive installed from the beginning, and we were only using about 150GB thus far, so we figured we still had a while before it ran out. That was before we ripped out first blu-ray disc. It ended up being around 30GB after we got done ripping, and after compressing the video further in handbrake it we got it to around 20GB. The Ultra HD Blu-ray discs were closer to 50GB! So, our estimate on how long the server would last quickly dropped.
-
-While we *were* using more space quickly, we still never surpassed 1TB. This wouldn't happen for another year or so. Around the fall of 2020, I left for college, and as things began to open up more permanently buying and ripping movies started to fall to the wayside once again. We had spurts of buying and ripping discs, but nothing too often. However, we were starting to run into issues streaming out UHD content. It would buffer quite often. We figured this was a sympotom of our WIFI link being slow, but in hindsight this may not have been the case. We've been wanting to upgrade the machine for a while, but never had any reason (or the time) to do so just yet. My dad brought home a decomissioned server from his office that had 6 1TB drives in it. One day we'd move everything over, but now wasn't the time.
-
-## A Breaking Point
-
-Just this past Christmas (2021), we ran into a breaking point. I was gifted a box set containing the full series of *The Office* (because it was taken off of Netflix for the sole reason of promoting Peacock, so I refuse to use Peacock), so I wanted to put it on the server before I left for college again. I got through about 3 seasons until I noticed the size of the folder: 250GB! This was huge, and I still had 6 seasons to go, probably was going to be around 850-900GB of content in total. This was never going to fit on the current server, which probably had about 90GB still free on it. We had to finally implement this new server. However, we didn't want to do it haphazardly. We were going to do this right (or at least as right as we know how).
-
-## Planning the Solution
-
-So, we had this server that had a total of 6TB of storage and 32GB of RAM. This was *more* than enough for our needs. Since we were also looking to overhaul our home network, we decided to do both at the same time.
@@ -0,0 +1,28 @@
+---
+title: "Guix Part 0 - Introduction"
+date: 2025-06-17T08:15:00-04:00
+draft: false
+type: posts
+---
+
+# Preface
+
+Welp, I am finally getting started with writing about Guix... This has been sitting in the back of my mind ever since I announced I was going to do it all the way back in... May.. of 2023. Woops. Sorry about that. I'll be honest, I still don't feel _completely_ ready to be writing something like this, but at the end of the day, I don't think I'll ever be. It's that feeling of "I could always know this a little deeper, a little more complete." that has been holding me back. However, I think at this point, I can safely say I know the absolute _basics_. Most of the main concepts I will talk about, even though I'm specifically referring to Guix, can even be transferred over to NixOS. If you find this series useful, please reach out and let me know, I'd love to hear :). Without _further_ ado, let's begin!
+
+# Introduction
+
+As I stated previously, I switched over to using [Guix](https://guix.gnu.org) as my main Linux distribution around April of last year. Surprisingly (to me as much as everyone else), I've stuck with it and have since fallen in love with its ideals. The idea of functional package management has always been intriguing to me, given the state of package management on every other distro. Its always been the same: install the packages you need (or want to try), inevitably forget you installed about half of them, taking up space on your drive, run into :japanese_ogre: ***dependency hell*** :japanese_ogre:, and if you use more than one computer regularly (like a powerful desktop at home and a smaller, but more power efficient laptop on the go)-- good luck keeping them in sync with each other. For example, my workflow consists of two computers: my main laptop that I keep docked at home due to its battery life, and a secondary I carry around with me... again for its battery life. Throughout college, I would switch between them through the day. Do a little homework on the go, do a little more when I get home, etc. Which was fine, I sync my files with either Git (if coding) or Syncthing (general purpose files). However, the biggest issue I would constantly run into (especially in the type of work I usually find myself doing) is inconsistent state of my machines. What exactly does this mean? Well, imagine this: You have an assignment to complete. To do this assignment, you need to install some external software of some kind to do this. Sometimes, this software may be custom/prioprietary/require custom configuration/anything else that may happen. So, you spend the first hour of homework simply getting your environment to work. You get it to work and go about your day. You get home to continue your hard work aaaaand...... you need to install everything again.... No matter, you just did this earlier in the day (because you work hard and would never procrastinate.... right?), it should be a piece of cake to recreate your environment. However, your computers obviously aren't identical. Months and months of varied usage has caused them to diverge somewhat, try as you may to keep them somewhat the same, by syncing dotfiles for instance. So, you try to recreate your environment aaaaand, it's broke. Why's this, I did the *exact* same steps on my other computer. Turns out I updated this other computer more recently, causing an incompatibility of some kind. Let's try and fix it.... 30 minutes of sunk time later and I either get it working or I just switch to my other computer again. Anyways, hopefully that illustrates the point I'm trying to make: computer's by default are inherentely *stateful* and, while I'm not saying state is bad outright (it's absolutely necessary to actually do anything useful!), maybe some less imperative state could be beneficial. Now, where does Nix/Guix come into this? Imagine the same scenario as last time, however one important change: you are now running Guix and your system is *entirely* configured (programs installed, dotfiles, even the bootloader) declaratively (more on that in a moment). You make changes by updating files, and those exact changes are synced over to your other computer and applied. Now, all of a sudden, you no longer have this issue of systems that don't behave exactly the same, because for all intents and purposes *they are exactly the same* (provably, in fact!)
+
+# Imperative v. Declarative
+
+So, I described the system being described *declaratively* above. What exactly does this mean? Well, most systems (Linux, macOS, Windows, etc.) are all designed on an *imperative* model. The systems are inherintely stateful, and making changes requires running commands in a certain order to reach a desired state. For example, say I wanted a computer to have Firefox, NeoVim, git, and Wireshark to be installed. I would need to either go to all of these product's websites (in the case of Windows) or run the appropriate commands in my terminal (like `apt`, `dnf`, `pacman`, etc.) in the case of Linux to actually get my system to this desired state. Then, if I want to replicate that state on another computer, I would need to: 1. Start at a common point (to guarantee the end state is the same), 2. Hope that packages haven't been updated (or pin them somehow), 3. Run the commands in the same order. Take all of that, in contrast, with declarative computing. In that case, you define an *end state*. For example, I would create a file that would describe my desired end state, not really caring what has to be done to actually get there. I would say "I want firefox, NeoVim, git, and Wireshark of versions x installed" and whatever backend is being used would figure out how to get my device to this end state. The best (and most well known) example of these principles (sort of...) would be Ansible. By default, you make playbooks that describe how you want a system to be set up (what files present, what packages installed, etc.) and it figures out how to get to this desired state. You don't really need to worry about the individual commands, per se.
+
+# Getting started
+
+So, with all of that said, how do you get started with using Guix or Nix? Well, first you actually need to choose one or the other (sorta, more on that in later posts!) So how do you actually choose between the two? Well, it's mostly an ideological choice at the end of the day, but there is one key difference. Nix was the original package manager, where NixOS was built around it. Around 2012, Ludovic Courtès released the first version of Guix (a play on the words Guile and Nix, which sort of describes its main selling point) as a component of the "GNU system". Two key differences between Guix and Nix are: Nix uses it's own language to describe derivations, Guix extends on Lisp, specifically *Scheme*, to describe derivations. Personally, I prefer using Scheme since it is already a functional language, by design. Plus, I have the power of the entire Scheme ecosystem behind me. Second, Guix focuses *very* purely on free software, where non-free software isn't even packaged (think like Discord, default Google Chrome, etc.) and it uses the Linux-libre kernel by default. On the other hand, Nix also focuses on free software but there is an option you can toggle to allow non-free software to be installed. However, with free software comes the freedom to do what you want with it, like installing non-free software anyways :smile:. So, I personally chose Guix since its paradigms checked more of my boxes, per se.
+
+# Coming soon...
+
+Given the length of this post has already ballooned more than I was expecting, I will be starting the actual Guix installation guide in Part 1 of this guide. Afterwards, I'll be delving into managing a home environment with Guix, then finally I will be making a series of posts describing how to actually hack Guix to make it purely your own (as well as hack it to contribute back for the greater good of everyone!)
+
+Until next time!
@@ -0,0 +1,30 @@
+---
+title: "Guix Part 1 - Installation Guide"
+date: 2025-07-24T00:00:00-04:00
+draft: true
+type: posts
+---
+
+So, you've decided you want to take the plunge and try out this distribution? Nice. It will be a challenging, but rewarding experience (as I have found over the last few years). First things first, you will need to install it to try it out, there's not really a concept of a "live" distro here. Plus, installing this distro in the usual way you'd expect will lead to some issues early on, especially if you use the default upstream ISO (it uses `linux-libre`, which lacks a lot of drivers, especially in the wireless networking department) that will hinder your progress. To solve this, this guide is written with the assumption (and guidance) to use an alternate ISO: the one provided by SystemCrafters (another great resource for Guix, they have a YouTube channel!
+
+# Preparation
+
+First, you will need the installation ISO. First, go to the [releases page for the SystemCrafters image]() and download the latest one available. Note: this build breaks from time to time, even if it is out of date for a while, your installation will still be completely up-to-date once installed since package versions are derived from an upstream repository; the official one. It will just take a little longer to actually install. Plus, even though you are using an alternate ISO, everything is still completely safe. The difference between it and the default ISO are listed on each release, and if you really wanted to you could install the default image on a VM and make the alternate ISO yourself. Its main difference is that it:
+
+- Uses the mainline linux kernel
+- Has the non-guix channel activated by default, a repository for "non-free" software (like Firefox due to licensing, Steam, mainline linux, etc.)
+
+Once you have this ISO downloaded and burned onto a USB using your method of choice, you are ready to install! Reboot your computer and boot into the installation environment. You will know you are ready to proceed when you see this screen
+
+<!-- Note: Image of default splash during installation here -->
+
+# Performing the installation
+
+Now, what you do here depends on a few things:
+
+- Do you have to use Wi-Fi?
+ - Use the graphical installer until you have your wifi set up at the very least to avoid manually configuring `wpa_supplicant`, at which case you can either continue using this installer or bail out to the terminal.
+- Do you want an encrypted drive?
+ - If so, follow the manual steps below since some defaults are not great
+- Do you want a standard installation (single partition, ext4, no encryption)
+ - Great, you can use the automated installer for most of this, but I would still use the manual steps for the actual installation, see [here]().
@@ -0,0 +1,16 @@
+---
+title: "Coming Soon!"
+date: 2023-05-17T13:00:00-05:00
+draft: false
+---
+
+# I am back! (for now)
+
+Hello all, I must say, it's been quite a while.... I've been quite busy, between school and working, so I haven't had the time to properly maintain this site like I would have wanted to. However, that is going to change (at least for this summer)! If you have been looking at the [Github repository for this site](https://github.com/ryan77627/rschanzorg-public), you will have noticed there are a few posts that are still drafts. Throughout the summer, I plan to:
+
+- Finish and release the draft posts I had began to write
+- Create a new series of posts outlining my experiences with [GNU Guix](https://guix.gnu.org), a Linux Distribution I have been migrating to and have been daily driving for the past month and a half at this point.
+
+The GNU Guix Series will mostly be my experiences in trying to learn the best practices in how to use the operating system (since it is declarative like NixOS), my general thought process while doing things (showing why my train of thought may not have been correct at time too), and showing how to do some common things with Guix that I have found little to no proper documentation on, like getting Pipewire to work properly (even with Bluetooth support!) So, stay tuned, as it will be a long (but fun!) ride.
+
+I will be releasing these posts every few weeks, with my first draft being released some time next week!
@@ -0,0 +1,34 @@
+---
+title: "De-googling my Life"
+date: 2023-06-13T08:00:00-04:00
+draft: false
+type: posts
+---
+
+## Preface
+
+This is a one-off piece not intended to be the second article referred to in my [home media server upgrade]("/projects/media_server") article, but rather a collection of my thoughts and process surrounding the circumstances that led me to "De-Google" my life. A bit of a disclaimer, I made all of my decisions considering what would be best for my situation: This is not meant to be a guide. While it can be used as a framework, copy and pasting things verbatim will almost certainly not work out how you would expect :wink:. With all of that out of the way, let's begin the story!
+
+## Introduction
+
+I started my journey to disconnect myself from Google as much as possible around 1 year ago at the time of writing this piece. Looking at where I am today, I'm fairly content with the progress I've made so far. Before I started this project, I used Google for everything. Search, entertainment (in the form of YouTube), an email provider, storage solution (for random files *and* my photo gallery), Calendar provider, etc. You name it, and it was very probable I was using a Google service to fulfill the need. Now, don't get me wrong, Google is ***very*** convenient and is perfectly adequate for 99% of the population. It's just for people who tend to overthink about their privacy.... it can be an absolute nightmare. Putting all of your eggs into one basket is kind of scary to me. For example, what if Google goes down? This is a very, *very*, unlikely scenario, but it does happen. About once or twice every few years it seems (it doesn't seem to be published information, so take this with a grain of salt, it's my best estimate). No computer system, no matter how redundant, is infallible. Things will happen. Last time Google went down was the end of 2020 for about 1 hour. During this time, it's safe to say a good portion of at the very least the U.S. had to stop functioning. Imagine: business emails powered by Google, not able to send or even look at new messages. Even if they could, it wouldn't matter, anyone using Gmail had this same issue. Almost no one could get to their email, nothing could be done. Any data on Google Drive is suddenly inaccesible. Eventually, half of the internet is inaccesible due to running on GCP. When Google goes down, a good portion of the internet goes with it. Everyone's eggs were in a singular basket, and when that basket broke, everyone's eggs fell out. Now, I'm not saying that moving away from Google will instantly solve this issue. Not in the slightest. You are still running on *some* computer, whether it's one you rent or one you own. However, the benefits are that you won't be at the mercy of whatever may be happening somewhere you don't have control over, especially if you host things personally.
+
+Secondly, which I feel is the most important part: Google is an *advertisement and search company*. It's in their best interest to know everything about you so they can give you the most relevant search results and advertisements. This can be inherently useful to getting you relevant information fast. However, as this is Google's main source of revenue, it is really in their best interest to know **as much as possible.** Where can they collect this data? Anywhere you use their services: Google itself, YouTube, Android (as a platform itself, Google is baked quite deep in there), Gmail (all that online shopping you did? Google knows what you bought now!), Chrome (ever notice it absoutely *begs* you to sign in, sometimes signing you in browser-wide without your consent as soon as you sign into **any** Google service? Well, I wonder why. Maybe it has something to do [with this](https://blog.cryptographyengineering.com/2018/09/23/why-im-leaving-chrome/) or [this](https://www.justice.gov/opa/pr/justice-department-sues-google-monopolizing-digital-advertising-technologies)?). Anything you do under Google's eye can be used as more data points against you. Not only that, but websites serving Google Ads will also contribute to data collection, though to a lesser extent with tracking cookies being mostly eradicated very soon, though that doesn't mean it's impossible to track you still. Finally, with the advent of AI that started with the release of ChatGPT (not exactly, but it definitely came to the forefront with it) I am begining to have more and more reservations about storing all of my data (like photos and emails especially) with companies that are pushing to generate better and better AI models for themselves, because I wonder where the training data comes from.....
+
+I thought to myself "Why do I need to give up all of my privacy?" Is it really worth the extra effort to run my own services to keep a portion of my privacy? To me, it really is. It's more for the principle of the matter to me. I should be able to choose who gets my data and what I give them. No more, no less. So, how exactly did I get Google (mostly) out of my life? It really just started with wanting a solution to host my photos and grew from there.
+
+## Photo hosting
+
+Around the end of 2020, Google announced the end of Google Photos' free tier to be June 1, 2021. What this meant was the Google Photos backup that I had running on my phone in the background for the better part of 3-4 years at this point was about to start counting against my Google account's storage, which is 15GB. 15GB doesn't really go too far anymore, especially when you use Google Drive to store a random assortment of files as well, because it was "so convenient." I really didn't feel like paying Google *and* compressing my images, and with the falling costs of HDD based storage, I figured I would try to do it myself and see what happens.
+
+In comes [Photoprism](https://github.com/photoprism/photoprism), a FOSS image hosting solution that fills in the niceties of Google Photos quite nicely. Album creation, face detection, location based image searching, and live photo previews, to name a few features. They have a docker image, so it was easy enough to get running on my (measly) hardware, which was a Raspberry PI 4 (4GB model) at the time. So, I downloaded the Docker image, got my reverse-proxy set up to properly redirect the traffic to the instance, and downloaded my entire Google Photos library. Once I had it downloaded, I simply took the zip file, put it on my server, and extracted it to an ingestion folder as specified by Photoprism.
+
+Once it was all ready, I started the Docker container and just let it churn through my photos, which admittedly took the longest amount of time (about 8-9 hours). However, this is a one time task (at this scale) that had to categorize, run facial and object recognition, and generate metadata for quite a few photos (I do not have an exact number anymore, but it was probably close to 4000 photos/videos.) Now I have auto-backups set up through [Photosync](https://play.google.com/store/apps/details?id=com.touchbyte.photosync&hl=en_US&gl=US) that uploads photos during the night as my phone charges to Photoprism's WebDAV endpoint. Over the past 2 (almost 3!!!) years, this has been working great!
+
+## Expanding from there
+
+Ever since my self-hosting journey began, almost everything I use has been questioned with "Can I replace this?" Going back to "putting all of your eggs into one basket," per se. A lot has happened since I started writing this article, however some of the biggest in recent memory has been what has hapened with Twitter and what is happening with Reddit. Let's take a look at Reddit, for example. There is currently (as of June 13, 2023) a blackout of over 8000 subreddits, where these communities are completely inaccessible. Now, this is happening to make a point, which I wholeheartedly agree with. Third party apps shouldn't have been priced out, Reddit should have communicated better, they are shooting themselves in the foot, the whole nine yards. However, as I stated on [my Mastodon account the day before](https://social.ryan77627.xyz/@ryan/110534518378932252), I'm at a bit of a crossroads about the whole thing. All of that information is gone, some of it permanently (with the exception of archives, which are way harder to discover), which is... unfortunate, to say the least. It's sad that information is just gone and so many searches are going to return way less relevant information than they once would. Maybe we shouldn't rely on a company to host our conversations (while also trying their hardest to monetize us as much as possible at the same time?) That's what self-hosting comes down to in my opinion: wanting no one but yourself to be responsible for the data you choose to release (or not) onto the internet. That way, if anything happens, you know who you can point the finger towards at least. :)
+
+## Conclusion
+
+Hopefully this article wasn't too all over the place, being written over the span of two years and all. I had a lot of topics I wanted to at least touch on but not a whole lot of "flow" I wanted to include; wanted to avoid writing more of a book than I already have. Next article in the series this summer will probably talking about setting up Mastodon, the Fediverse in general, my thoughts on decentralized services and the like. Until then, I will see you all next time!
@@ -0,0 +1,46 @@
+---
+title: "GPG Key Update"
+date: 2022-02-21T01:50:00-05:00
+draft: false
+---
+
+Hello everyone! Writing this quick article to announce the rotation and subsequent retiring of my old GPG key to a new one! I'm doing this mainly because my key has grown rather large, and I'd like to transition my key from using a 4096-bit RSA key to a Ed25519 key, which should provide functionally the same amount of security (author of Ed25519 quotes it equivalent to ~3000 bit RSA key, but I do know that really isn't the best way to compare these two things :P )
+
+So, with this announcement, I'd like to make the following points:
+* My old key is not compromised, but will be revoked after making this announcement
+* I will *not* use my old key to sign things, encrypt things, or authenticate with anything from this point onwards. If I do, something is terribly wrong.
+* This new key has been cross signed by my old key, but I won't be cross signing my old key with my new one, since that seems to be a "can go either way" situation in this case, and I don't see the benefit as the key is being revoked regardless.
+
+This is the information of the key that is being revoked:
+```
+pub rsa4096 2020-09-29 [C]
+ 2BC5D27B47EE5632F97A668012FAE298AAD38D3D
+uid [ultimate] Ryan Schanzenbacher <ryan@rschanz.org>
+uid [ultimate] Ryan Schanzenbacher <rjs1877@rit.edu>
+uid [ultimate] Ryan Schanzenbacher <rschanzenbacher@stoicproductions.org>
+uid [ultimate] [jpeg image of size 3237]
+sub rsa4096 2020-09-29 [A] [expires: 2022-10-03]
+sub rsa4096 2020-09-29 [E] [expires: 2022-10-03]
+sub rsa4096 2020-09-29 [S] [expires: 2022-10-03]
+```
+
+And this is the information of my new key:
+```
+pub ed25519 2022-02-21 [C]
+ 3E8745425417A3E388ACD906067DC3463E17741C
+uid [ultimate] Ryan Schanzenbacher <ryan@rschanz.org>
+uid [ultimate] [jpeg image of size 4437]
+uid [ultimate] Ryan Schanzenbacher <rjs1877@rit.edu>
+uid [ultimate] Ryan Schanzenbacher <rschanzenbacher@stoicproductions.org>
+sub ed25519 2022-02-21 [S] [expires: 2023-02-21]
+sub cv25519 2022-02-21 [E] [expires: 2023-02-21]
+sub ed25519 2022-02-21 [A] [expires: 2023-02-21]
+```
+
+I'd recommend to update your keychains if you happen to have my key, and the key hosted on the homepage of this website has been updated to reflect my new key.
+
+[Here is the signed version of this message](/misc/gpg_key_rotation_signed.txt)
+
+If you have any questions/comments/concerns, you can reach out to me at ryan@rschanz.org.
+
+Thanks!
@@ -0,0 +1,15 @@
+---
+title: "Mastodon - Joining the Fediverse"
+date: 2022-11-24T02:58:58-05:00
+draft: true
+---
+
+# Preface
+
+Hey all, it's been a while! My last post was on Feb. 21 of this year, and it was just a small update surrounding the status of my GPG key. I've been... busy, to say the least these past 9 months. However, with Thanksgiving break here and Winter break just on the horizon, I'm going to be able to take a step back from everything I've been neck-deep in and catch up on some personal projects, like this website! I have a few articles that have been drafts for about 8 months now (which you could see if you just go to [the github that this website is built from.](https://github.com/ryan77627/rschanzorg-public)) Expect to see those stories coming in the next few months, if not sooner! Anyway, back to your (not so) regularly scheduled content!
+
+# Introduction
+
+So, I've heard about [Mastodon](https://joinmastodon.org) in passing for the better part of a few years now. However, for whatever reason I never decided to join it. Whether it be for the lack of users at the time, effort that I didn't want to put in (because if I'm going to use it I will do it the exact same way I manage my Matrix presense: I'll do it myself (more on that soon)! ) However, with the recent.... news about Twitter and just watching everything happen to it, I've had a renewed interest in Mastodon.
+
+My interest was sparked again by a mixture of hearing about it from friends in [RITLUG](https://ritlug.com), a club that I regularly attend and am secretary of at RIT, and from various internet sources. Hearing about a huge popularity spike made me excited: This is a great excuse to give it a shot! Plus, if I go on it, I can try to be a bit more "present" online -- posting tinier things more frequently, just to prove I'm still around :simple_smile:.
@@ -0,0 +1,44 @@
+---
+title: "Home Media Server"
+date: 2022-01-10T16:05:04-05:00
+draft: false
+type: posts
+---
+
+## Some History
+
+Now that I am coming off of my winter break, I'll finally have a chance to write about some of the things I was able to do over it. So, this post will be the first in a series of two detailing two big projects I worked on over the past 4 weeks. First, I'd like to talk about the bigger of the two projects: Rennovating my home media server. Around the summer of 2018, my Dad and I started to undertake the process of digitizing all of our media. Now, legal gray area aside, this was a success, and after almost a year of work we finally had most things digitized. Now, the goal was to eventually make everything available to the entire house. We weren't sure how to go about this, but I've heard of an application named "Kodi", so I installed a distribution of Ubuntu onto a spare computer named "Kodibuntu." This was easy enough to set up, and soon enough we had all of our songs and most of our movies stored on this machine, ready to be viewed at a moments notice.
+
+About 6 months after this was set up, and numerous crashes from Kodi, I started looking for a different solution. I was very passive in my search, I had schoolwork to focus on as well, so this project sort of hit the backburner for a while. However, one day I was scrolling through my Google Feed and saw a github page for a project named "Jellyfin" claiming to be useful for media servers. I took a look at the project and it filled all of our boxes! Self-hosted, auto indexing software for all of our media, all while providing a central interface to get everything from. So, one weekend I tore out Kodi and replaced it with Jellyfin; after all Kodibuntu was just Ubuntu with Kodi on top of it, so I had access to all of the Ubuntu Repos. After that, it just sat there, slowly collecting any new media we got, waiting for us to watch stuff from it (which we do all the time, we have an Android TV with the Jellyfin app, we watch things on there all the time!).
+
+## A Growing Problem
+
+Around mid-2020, our USB DVD reader died while ripping a DVD. This was unfortunate, but it was going on 3 years old at this point, it was probably its time. So, we decided it was time to upgrade. We ended up buying a USB Bluray drive so we could begin to rip HD and UHD content to our media server; I mean, the TV we had downstairs was a UHD TV, it was time to stop watching 480p DVDs on it. We had a 1TB drive installed from the beginning, and we were only using about 150GB thus far, so we figured we still had a while before it ran out. That was before we ripped out first blu-ray disc. It ended up being around 30GB after we got done ripping, and after compressing the video further in handbrake it we got it to around 20GB. The Ultra HD Blu-ray discs were closer to 50GB! So, our estimate on how long the server would last quickly dropped.
+
+While we *were* using more space quickly, we still never surpassed 1TB. This wouldn't happen for another year or so. Around the fall of 2020, I left for college, and as things began to open up more permanently buying and ripping movies started to fall to the wayside once again. We had spurts of buying and ripping discs, but nothing too often. However, we were starting to run into issues streaming out UHD content. It would buffer quite often. We figured this was a sympotom of our WIFI link being slow, but in hindsight this may not have been the case. We've been wanting to upgrade the machine for a while, but never had any reason (or the time) to do so just yet. My dad brought home a decomissioned server from his office that had 6 1TB drives in it. One day we'd move everything over, but now wasn't the time.
+
+## A Breaking Point
+
+Just this past Christmas (2021), we ran into a breaking point. I was gifted a box set containing the full series of *The Office* (because it was taken off of Netflix for the sole reason of promoting Peacock, so I refuse to use Peacock), so I wanted to put it on the server before I left for college again. I got through about 3 seasons until I noticed the size of the folder: 250GB! This was huge, and I still had 6 seasons to go, probably was going to be around 850-900GB of content in total. This was never going to fit on the current server, which probably had about 90GB still free on it. We had to finally implement this new server. However, we didn't want to do it haphazardly. We were going to do this right (or at least as right as we know how).
+
+## Planning the Solution
+
+So, we had this server that had a total of 6TB of storage and 32GB of RAM. This was *more* than enough for our needs. Since we were also looking to overhaul our home network, we decided to work on this as well. Ideally, we wanted to move all of our networking equipment into another room so it was out of our downstairs family room, making it look a lot nicer (and most likely more performant since the modem would be closer to where the coaxial cabling enters the house and we've historically had issues with noisy signal where we have it set up.)
+
+We took some time to jerry-rig a mount for the server (since we don't own a rack nor have a place for an entire rack) and start preparing to place the server there. While we were coming up with a mounting solution, I got started setting up the server.
+
+## The Build
+
+As mentioned previously, this machine was a decomissioned server from my dad's office. It was a backup server for their infrastructure in a past life. So, first thing I did was wipe everything off of it to start with a clean slate. Now, we wanted full redundancy with this new setup, so I had to come up with a solution. Since this machine happened to support EFI booting, I used that. Just note that the approach I used would have worked with BIOS booting as well, just some small differences in setup. We had 6 1TB drives that I split into two partitions each. 1 ~500MB partition for the EFI boot files and 1 partition for the rest of the space which would go into the main storage pool.
+
+Now, for full redundancy, I had to make sure *everything* got replicated, because if I just relied on one drive for booting that would be a single point of failure. Since every drive was the same size and partitioned exactly the same I was able to setup two RAIDs to solve this issue.
+
+## The RAID setup
+
+The method in which we setup our server is a bit unconventional (At least I think, I've never heard of a setup like this before). I used the beginning 500MB partitions as the EFI boot partition, duplicated among all 6 drives using mdadm's RAID1 and **metadata version 1.** The metadata version is the most important part of this setup. By using version 1, you avoid putting the mdadm headers at the beginning of the partition, meaning you can have your filesystem headers at the beginning instead, which is important if the motherboard firmware is to recognize these as proper boot partitions. Since the metadata is not at the front, I simply mounted the `/dev/md0` entry that was created after adding them all to an array and wrote my FAT32 filesystem with the proper flags set to it. Lo and behold, when I went back to look at the separate partitions, they all appeared to be "formatted" using the same FAT32 filesystem with the exact same data. Perfect! Our bootloader is fully redundant. I just added an entry for each drive in the motherboard's firmware so it will just run through all the drives and boot using the first one that's aailable, falling back if necessary.
+
+For the actual operating system, I used ZFS in a raidz1 setup. This is akin to a RAID5 array. It gives you one drive failure before you begin to lose any data. Since I was basing this install on Arch (I wanted to install the least number of packages possible, this is simply a base OS for KVM to manage virtual machines.), I installed the zfs-dkim package from the AUR and let it compile for my kernel. Once it was fully installed, I created the pool using the second partition from all the drives I had available. We were just going to make one big partition that contained the system and the VM images all in one. Once I made the volume that the system would reside on, I followed the Arch install guide just like any other regular install. The only deviations made were for generating the fstab entries and generating the initcpio image. I followed the Root on ZFS guide from the Arch wiki to generate those properly. Once my system was fully installed, I rebooted and..... nothing :slight_frown:. I booted back into the live usb I created a few more times, changing various settings to no avail. For whatever reason, the Arch initcpio wouldn't automatically mount our root partition and pivot into it. I could mount it manually just fine, but automounting did not work. Case in point, after a few hours, the fix was simple: just add `zfs=bootfs` to your grub boot entry. That solved our issue and we booted right to the OS.
+
+## Conclusion
+
+This was a really fun project for me to work on over the break. It really got me out of my comfort zone and put me into a new territory of Linux I've never explored before. Coming up with a solution completely on my own, figuring out how to execute it properly, and watching it slowly come to fruition has been very rewarding to say the least. I'm sure at some point we will expand this server again, and I'll probably have to re-learn a lot of things, but hopefully this article taught you (and me when I inevitably have to read through it to figure out what I did) something new :slight_smile:. At the very least, I hope it was an enjoyable read and really put you into my shoes, if not just for a little bit.
@@ -0,0 +1 @@
+body.colorscheme-dark{color:#dadada;background-color:#212121}body.colorscheme-dark a{color:#42a5f5}body.colorscheme-dark h1,body.colorscheme-dark h2,body.colorscheme-dark h3,body.colorscheme-dark h4,body.colorscheme-dark h5,body.colorscheme-dark h6{color:#dadada}body.colorscheme-dark h1:hover .heading-link,body.colorscheme-dark h2:hover .heading-link,body.colorscheme-dark h3:hover .heading-link,body.colorscheme-dark h4:hover .heading-link,body.colorscheme-dark h5:hover .heading-link,body.colorscheme-dark h6:hover .heading-link{visibility:visible}body.colorscheme-dark h1 .heading-link,body.colorscheme-dark h2 .heading-link,body.colorscheme-dark h3 .heading-link,body.colorscheme-dark h4 .heading-link,body.colorscheme-dark h5 .heading-link,body.colorscheme-dark h6 .heading-link{color:#42a5f5;font-weight:inherit;text-decoration:none;font-size:80%;visibility:hidden}body.colorscheme-dark h1 .title-link,body.colorscheme-dark h2 .title-link,body.colorscheme-dark h3 .title-link,body.colorscheme-dark h4 .title-link,body.colorscheme-dark h5 .title-link,body.colorscheme-dark h6 .title-link{color:inherit;font-weight:inherit;text-decoration:none}body.colorscheme-dark code{background-color:#424242;color:#dadada}body.colorscheme-dark pre code{background-color:inherit;color:inherit}body.colorscheme-dark blockquote{border-left:2px solid #424242}body.colorscheme-dark table td,body.colorscheme-dark table th{border:2px solid #dadada}@media(prefers-color-scheme:dark){body.colorscheme-auto{color:#dadada;background-color:#212121}body.colorscheme-auto a{color:#42a5f5}body.colorscheme-auto h1,body.colorscheme-auto h2,body.colorscheme-auto h3,body.colorscheme-auto h4,body.colorscheme-auto h5,body.colorscheme-auto h6{color:#dadada}body.colorscheme-auto h1:hover .heading-link,body.colorscheme-auto h2:hover .heading-link,body.colorscheme-auto h3:hover .heading-link,body.colorscheme-auto h4:hover .heading-link,body.colorscheme-auto h5:hover .heading-link,body.colorscheme-auto h6:hover .heading-link{visibility:visible}body.colorscheme-auto h1 .heading-link,body.colorscheme-auto h2 .heading-link,body.colorscheme-auto h3 .heading-link,body.colorscheme-auto h4 .heading-link,body.colorscheme-auto h5 .heading-link,body.colorscheme-auto h6 .heading-link{color:#42a5f5;font-weight:inherit;text-decoration:none;font-size:80%;visibility:hidden}body.colorscheme-auto h1 .title-link,body.colorscheme-auto h2 .title-link,body.colorscheme-auto h3 .title-link,body.colorscheme-auto h4 .title-link,body.colorscheme-auto h5 .title-link,body.colorscheme-auto h6 .title-link{color:inherit;font-weight:inherit;text-decoration:none}body.colorscheme-auto code{background-color:#424242;color:#dadada}body.colorscheme-auto pre code{background-color:inherit;color:inherit}body.colorscheme-auto blockquote{border-left:2px solid #424242}body.colorscheme-auto table td,body.colorscheme-auto table th{border:2px solid #dadada}}body.colorscheme-dark .content .post .tags .tag{background-color:#424242}body.colorscheme-dark .content .post .tags .tag a{color:#dadada}body.colorscheme-dark .content .post .tags .tag a:active{color:#dadada}body.colorscheme-dark .content .list ul li .title{color:#dadada}body.colorscheme-dark .content .list ul li .title:hover,body.colorscheme-dark .content .list ul li .title:focus{color:#42a5f5}body.colorscheme-dark .content .centered .about ul li a{color:#dadada}body.colorscheme-dark .content .centered .about ul li a:hover,body.colorscheme-dark .content .centered .about ul li a:focus{color:#42a5f5}@media(prefers-color-scheme:dark){body.colorscheme-auto .content .post .tags .tag{background-color:#424242}body.colorscheme-auto .content .post .tags .tag a{color:#dadada}body.colorscheme-auto .content .post .tags .tag a:active{color:#dadada}body.colorscheme-auto .content .list ul li .title{color:#dadada}body.colorscheme-auto .content .list ul li .title:hover,body.colorscheme-auto .content .list ul li .title:focus{color:#42a5f5}body.colorscheme-auto .content .centered .about ul li a{color:#dadada}body.colorscheme-auto .content .centered .about ul li a:hover,body.colorscheme-auto .content .centered .about ul li a:focus{color:#42a5f5}}body.colorscheme-dark .notice .notice-title{border-bottom:1px solid #212121}@media(prefers-color-scheme:dark){body.colorscheme-auto .notice .notice-title{border-bottom:1px solid #212121}}body.colorscheme-dark .navigation a,body.colorscheme-dark .navigation span{color:#dadada}body.colorscheme-dark .navigation a:hover,body.colorscheme-dark .navigation a:focus{color:#42a5f5}@media only screen and (max-width:768px){body.colorscheme-dark .navigation .navigation-list{background-color:#212121;border-top:solid 2px #424242;border-bottom:solid 2px #424242}}@media only screen and (max-width:768px){body.colorscheme-dark .navigation .navigation-list .menu-separator{border-top:2px solid #dadada}}@media only screen and (max-width:768px){body.colorscheme-dark .navigation #menu-toggle:checked+label>i{color:#424242}}body.colorscheme-dark .navigation i{color:#dadada}body.colorscheme-dark .navigation i:hover,body.colorscheme-dark .navigation i:focus{color:#42a5f5}body.colorscheme-dark .navigation .menu-button i:hover,body.colorscheme-dark .navigation .menu-button i:focus{color:#dadada}@media(prefers-color-scheme:dark){body.colorscheme-auto .navigation a,body.colorscheme-auto .navigation span{color:#dadada}body.colorscheme-auto .navigation a:hover,body.colorscheme-auto .navigation a:focus{color:#42a5f5}}@media only screen and (prefers-color-scheme:dark) and (max-width:768px){body.colorscheme-auto .navigation .navigation-list{background-color:#212121;border-top:solid 2px #424242;border-bottom:solid 2px #424242}}@media only screen and (prefers-color-scheme:dark) and (max-width:768px){body.colorscheme-auto .navigation .navigation-list .menu-separator{border-top:2px solid #dadada}}@media only screen and (prefers-color-scheme:dark) and (max-width:768px){body.colorscheme-auto .navigation #menu-toggle:checked+label>i{color:#424242}}@media(prefers-color-scheme:dark){body.colorscheme-auto .navigation i{color:#dadada}body.colorscheme-auto .navigation i:hover,body.colorscheme-auto .navigation i:focus{color:#42a5f5}body.colorscheme-auto .navigation .menu-button i:hover,body.colorscheme-auto .navigation .menu-button i:focus{color:#dadada}}body.colorscheme-dark .taxonomy-element{background-color:#424242}body.colorscheme-dark .taxonomy-element a{color:#dadada}body.colorscheme-dark .taxonomy-element a:active{color:#dadada}@media(prefers-color-scheme:dark){body.colorscheme-auto .taxonomy-element{background-color:#424242}body.colorscheme-auto .taxonomy-element a{color:#dadada}body.colorscheme-auto .taxonomy-element a:active{color:#dadada}}body.colorscheme-dark .footer a{color:#42a5f5}@media(prefers-color-scheme:dark){body.colorscheme-auto .footer a{color:#42a5f5}}body.colorscheme-dark .float-container a{color:#dadada;background-color:#424242}body.colorscheme-dark .float-container a:hover,body.colorscheme-dark .float-container a:focus{color:#42a5f5}@media only screen and (max-width:768px){body.colorscheme-dark .float-container a:hover,body.colorscheme-dark .float-container a:focus{color:#dadada}}@media(prefers-color-scheme:dark){body.colorscheme-auto .float-container a{color:#dadada;background-color:#424242}body.colorscheme-auto .float-container a:hover,body.colorscheme-auto .float-container a:focus{color:#42a5f5}}@media only screen and (prefers-color-scheme:dark) and (max-width:768px){body.colorscheme-auto .float-container a:hover,body.colorscheme-auto .float-container a:focus{color:#dadada}}
\ No newline at end of file
@@ -0,0 +1 @@
+{"Target":"css/coder-dark.min.aa883b9ce35a8ff4a2a5008619005175e842bb18a8a9f9cc2bbcf44dab2d91fa.css","MediaType":"text/css","Data":{"Integrity":"sha256-qog7nONaj/SipQCGGQBRdehCuxioqfnMK7z0Tastkfo="}}
\ No newline at end of file
@@ -0,0 +1,6 @@
+@charset "UTF-8";/*!normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css*/html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;word-wrap:break-word}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}/*!Fork Awesome 1.2.0
+License - https://forkaweso.me/Fork-Awesome/license
+Copyright 2018 Dave Gandy & Fork Awesome
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/@font-face{font-family:forkawesome;src:url(../fonts/forkawesome-webfont.eot?v=1.2.0);src:url(../fonts/forkawesome-webfont.eot?#iefix&v=1.2.0)format("embedded-opentype"),url(../fonts/forkawesome-webfont.woff2?v=1.2.0)format("woff2"),url(../fonts/forkawesome-webfont.woff?v=1.2.0)format("woff"),url(../fonts/forkawesome-webfont.ttf?v=1.2.0)format("truetype"),url(../fonts/forkawesome-webfont.svg?v=1.2.0#forkawesomeregular)format("svg");font-weight:400;font-style:normal;font-display:block}.fa{display:inline-block;font:14px/1 ForkAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-sync:before,.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video:before,.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell-o:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-globe-e:before{content:"\f304"}.fa-globe-w:before{content:"\f305"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-community:before,.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus-g:before,.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-utensils:before,.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-pound:before,.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-down:before,.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-up:before,.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-down:before,.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-up:before,.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-down:before,.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-up:before,.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-utensil-spoon:before,.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-heading:before,.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-closed-captioning:before,.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-gem:before,.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-medium-square:before{content:"\f2f8"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo-v:before,.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.fa-mastodon:before{content:"\f2e1"}.fa-mastodon-alt:before{content:"\f2e2"}.fa-fork-circle:before,.fa-fork-awesome:before{content:"\f2e3"}.fa-peertube:before{content:"\f2e4"}.fa-diaspora:before{content:"\f2e5"}.fa-friendica:before{content:"\f2e6"}.fa-gnu-social:before{content:"\f2e7"}.fa-liberapay-square:before{content:"\f2e8"}.fa-liberapay:before{content:"\f2e9"}.fa-ssb:before,.fa-scuttlebutt:before{content:"\f2ea"}.fa-hubzilla:before{content:"\f2eb"}.fa-social-home:before{content:"\f2ec"}.fa-artstation:before{content:"\f2ed"}.fa-discord:before{content:"\f2ee"}.fa-discord-alt:before{content:"\f2ef"}.fa-patreon:before{content:"\f2f0"}.fa-snowdrift:before{content:"\f2f1"}.fa-activitypub:before{content:"\f2f2"}.fa-ethereum:before{content:"\f2f3"}.fa-keybase:before{content:"\f2f4"}.fa-shaarli:before{content:"\f2f5"}.fa-shaarli-o:before{content:"\f2f6"}.fa-cut-key:before,.fa-key-modern:before{content:"\f2f7"}.fa-xmpp:before{content:"\f2f9"}.fa-archive-org:before{content:"\f2fc"}.fa-freedombox:before{content:"\f2fd"}.fa-facebook-messenger:before{content:"\f2fe"}.fa-debian:before{content:"\f2ff"}.fa-mastodon-square:before{content:"\f300"}.fa-tipeee:before{content:"\f301"}.fa-react:before{content:"\f302"}.fa-dogmazic:before{content:"\f303"}.fa-zotero:before{content:"\f309"}.fa-nodejs:before{content:"\f308"}.fa-nextcloud:before{content:"\f306"}.fa-nextcloud-square:before{content:"\f307"}.fa-hackaday:before{content:"\f30a"}.fa-laravel:before{content:"\f30b"}.fa-signalapp:before{content:"\f30c"}.fa-gnupg:before{content:"\f30d"}.fa-php:before{content:"\f30e"}.fa-ffmpeg:before{content:"\f30f"}.fa-joplin:before{content:"\f310"}.fa-syncthing:before{content:"\f311"}.fa-inkscape:before{content:"\f312"}.fa-matrix-org:before{content:"\f313"}.fa-pixelfed:before{content:"\f314"}.fa-bootstrap:before{content:"\f315"}.fa-dev-to:before{content:"\f316"}.fa-hashnode:before{content:"\f317"}.fa-jirafeau:before{content:"\f318"}.fa-emby:before{content:"\f319"}.fa-wikidata:before{content:"\f31a"}.fa-gimp:before{content:"\f31b"}.fa-c:before{content:"\f31c"}.fa-digitalocean:before{content:"\f31d"}.fa-att:before{content:"\f31e"}.fa-gitea:before{content:"\f31f"}.fa-file-epub:before{content:"\f321"}.fa-python:before{content:"\f322"}.fa-archlinux:before{content:"\f323"}.fa-pleroma:before{content:"\f324"}.fa-unsplash:before{content:"\f325"}.fa-hackster:before{content:"\f326"}.fa-spell-check:before{content:"\f327"}.fa-moon:before{content:"\f328"}.fa-sun:before{content:"\f329"}.fa-f-droid:before{content:"\f32a"}.fa-biometric:before{content:"\f32b"}.fa-wire:before{content:"\f32c"}.fa-tor-onion:before{content:"\f32e"}.fa-volume-mute:before{content:"\f32f"}.fa-bell-ringing:before{content:"\f32d"}.fa-bell-ringing-o:before{content:"\f330"}.fa-hal:before{content:"\f333"}.fa-jupyter:before{content:"\f335"}.fa-julia:before{content:"\f334"}.fa-classicpress:before{content:"\f331"}.fa-classicpress-circle:before{content:"\f332"}.fa-open-collective:before{content:"\f336"}.fa-orcid:before{content:"\f337"}.fa-researchgate:before{content:"\f338"}.fa-funkwhale:before{content:"\f339"}.fa-askfm:before{content:"\f33a"}.fa-blockstack:before{content:"\f33b"}.fa-boardgamegeek:before{content:"\f33c"}.fa-bunny:before{content:"\f35f"}.fa-buymeacoffee:before{content:"\f33d"}.fa-cc-by:before{content:"\f33e"}.fa-creative-commons-alt:before,.fa-cc-cc:before{content:"\f33f"}.fa-cc-nc-eu:before{content:"\f341"}.fa-cc-nc-jp:before{content:"\f342"}.fa-cc-nc:before{content:"\f340"}.fa-cc-nd:before{content:"\f343"}.fa-cc-pd:before{content:"\f344"}.fa-cc-remix:before{content:"\f345"}.fa-cc-sa:before{content:"\f346"}.fa-cc-share:before{content:"\f347"}.fa-cc-zero:before{content:"\f348"}.fa-conway-hacker:before,.fa-conway-glider:before{content:"\f349"}.fa-csharp:before{content:"\f34a"}.fa-email-bulk:before{content:"\f34b"}.fa-email-bulk-o:before{content:"\f34c"}.fa-gnu:before{content:"\f34d"}.fa-google-play:before{content:"\f34e"}.fa-heroku:before{content:"\f34f"}.fa-hassio:before,.fa-home-assistant:before{content:"\f350"}.fa-java:before{content:"\f351"}.fa-mariadb:before{content:"\f352"}.fa-markdown:before{content:"\f353"}.fa-mysql:before{content:"\f354"}.fa-nordcast:before{content:"\f355"}.fa-plume:before{content:"\f356"}.fa-postgresql:before{content:"\f357"}.fa-sass-alt:before{content:"\f359"}.fa-sass:before{content:"\f358"}.fa-skate:before{content:"\f35a"}.fa-sketchfab:before{content:"\f35b"}.fa-tex:before{content:"\f35c"}.fa-textpattern:before{content:"\f35d"}.fa-unity:before{content:"\f35e"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#212121;background-color:#fafafa;font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,Helvetica,pingfang sc,STXihei,华文细黑,microsoft yahei,微软雅黑,SimSun,宋体,Heiti,黑体,sans-serif;font-size:1.8em;font-weight:400;line-height:1.8em}@media only screen and (max-width:768px){body{font-size:1.6em;line-height:1.6em}}a{font-weight:500;color:#1565c0;text-decoration:none;transition:all .25s ease-in}a:focus,a:hover{text-decoration:underline}p{margin:2rem 0}h1,h2,h3,h4,h5,h6{font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,Helvetica,pingfang sc,STXihei,华文细黑,microsoft yahei,微软雅黑,SimSun,宋体,Heiti,黑体,sans-serif;font-weight:600;color:#000;margin:4rem 0 2.5rem}h1:hover .heading-link,h2:hover .heading-link,h3:hover .heading-link,h4:hover .heading-link,h5:hover .heading-link,h6:hover .heading-link{visibility:visible}h1 .heading-link,h2 .heading-link,h3 .heading-link,h4 .heading-link,h5 .heading-link,h6 .heading-link{color:#1565c0;font-weight:inherit;text-decoration:none;font-size:80%;visibility:hidden}h1 .title-link,h2 .title-link,h3 .title-link,h4 .title-link,h5 .title-link,h6 .title-link{color:inherit;font-weight:inherit;text-decoration:none}h1{font-size:3.2rem;line-height:3.6rem}@media only screen and (max-width:768px){h1{font-size:3rem;line-height:3.4rem}}h2{font-size:2.8rem;line-height:3.2rem}@media only screen and (max-width:768px){h2{font-size:2.6rem;line-height:3rem}}h3{font-size:2.4rem;line-height:2.8rem}@media only screen and (max-width:768px){h3{font-size:2.2rem;line-height:2.6rem}}h4{font-size:2.2rem;line-height:2.6rem}@media only screen and (max-width:768px){h4{font-size:2rem;line-height:2.4rem}}h5{font-size:2rem;line-height:2.4rem}@media only screen and (max-width:768px){h5{font-size:1.8rem;line-height:2.2rem}}h6{font-size:1.8rem;line-height:2.2rem}@media only screen and (max-width:768px){h6{font-size:1.6rem;line-height:2rem}}b,strong{font-weight:700}.highlight>div,.highlight>pre{margin:0 0 2rem;padding:1rem;border-radius:1rem}pre{display:block;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1.6rem;font-weight:400;line-height:2.6rem;overflow-x:auto;margin:0}pre code{display:inline-block;background-color:inherit;color:inherit}code{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1.6rem;font-weight:400;background-color:#e0e0e0;color:#212121;border-radius:.6rem;padding:.3rem .6rem}blockquote{border-left:2px solid #e0e0e0;padding-left:2rem;line-height:2.2rem;font-weight:400;font-style:italic}th,td{padding:1.6rem}table{border-collapse:collapse}table td,table th{border:2px solid #000}table tr:first-child th{border-top:0}table tr:last-child td{border-bottom:0}table tr td:first-child,table tr th:first-child{border-left:0}table tr td:last-child,table tr th:last-child{border-right:0}img{max-width:100%}figure{text-align:center}.preload-transitions *{-webkit-transition:none!important;-moz-transition:none!important;-ms-transition:none!important;-o-transition:none!important;transition:none!important}.wrapper{display:flex;flex-direction:column;min-height:100vh;width:100%}.container{margin:1rem auto;max-width:90rem;width:100%;padding-left:2rem;padding-right:2rem}.fab{font-weight:400}.fas{font-weight:700}.float-right{float:right}.float-left{float:left}.fab{font-weight:400}.fas{font-weight:900}img.emoji{height:1em;width:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.content{flex:1;display:flex;margin-top:1.6rem;margin-bottom:3.2rem}.content article details summary{cursor:pointer}.content article header{margin-top:6.4rem;margin-bottom:3.2rem}.content article header h1{font-size:4.2rem;line-height:4.6rem;margin:0}@media only screen and (max-width:768px){.content article header h1{font-size:4rem;line-height:4.4rem}}.content article footer{margin-top:4rem}.content article footer .see-also{margin:3.2rem 0}.content article footer .see-also h3{margin:3.2rem 0}.content article p{text-align:justify;text-justify:auto;hyphens:auto}.content .post .post-title{margin-bottom:.75em}.content .post .post-meta i{text-align:center;width:1.6rem;margin-left:0;margin-right:.5rem}.content .post .post-meta .date .posted-on{margin-left:0;margin-right:1.5rem}.content .post .post-meta .tags .tag{display:inline-block;padding:.3rem .6rem;background-color:#e0e0e0;border-radius:.6rem;line-height:1.4em}.content .post .post-meta .tags .tag a{color:#212121}.content .post .post-meta .tags .tag a:active{color:#212121}.content figure{margin:0;padding:0}.content figcaption p{text-align:center;font-style:italic;font-size:1.6rem;margin:0}.avatar img{width:20rem;height:auto;border-radius:50%}@media only screen and (max-width:768px){.avatar img{width:10rem}}.list ul{margin:3.2rem 0;list-style:none;padding:0}.list ul li{font-size:1.8rem}@media only screen and (max-width:768px){.list ul li{margin:1.6rem 0}}.list ul li .date{display:inline-block;flex:1;width:20rem;text-align:right;margin-right:3rem}@media only screen and (max-width:768px){.list ul li .date{display:block;text-align:left}}.list ul li .title{font-size:1.8rem;flex:2;color:#212121;font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,Helvetica,pingfang sc,STXihei,华文细黑,microsoft yahei,微软雅黑,SimSun,宋体,Heiti,黑体,sans-serif;font-weight:700}.list ul li .title:hover,.list ul li .title:focus{color:#1565c0}@media only screen and (min-width:768.1px){.list ul:not(.pagination) li{display:flex}}.centered{display:flex;align-items:center;justify-content:center}.centered .about{text-align:center}.centered .about h1{margin-top:2rem;margin-bottom:.5rem}.centered .about h2{margin-top:1rem;margin-bottom:.5rem;font-size:2.4rem}@media only screen and (max-width:768px){.centered .about h2{font-size:2rem}}.centered .about ul{list-style:none;margin:3rem 0 1rem;padding:0}.centered .about ul li{display:inline-block;position:relative}.centered .about ul li a{color:#212121;text-transform:uppercase;margin-left:1rem;margin-right:1rem;font-size:1.6rem}.centered .about ul li a:hover,.centered .about ul li a:focus{color:#1565c0}@media only screen and (max-width:768px){.centered .about ul li a{font-size:1.4rem}}.centered .about ul li a i{font-size:3.2rem}.centered .error{text-align:center}.centered .error h1{margin-top:2rem;margin-bottom:.5rem;font-size:4.6rem}@media only screen and (max-width:768px){.centered .error h1{font-size:3.2rem}}.centered .error h2{margin-top:2rem;margin-bottom:3.2rem;font-size:3.2rem}@media only screen and (max-width:768px){.centered .error h2{font-size:2.8rem}}.notice{border-radius:.2rem;position:relative;margin:2rem 0;padding:0 .75rem;overflow:auto}.notice .notice-title{position:relative;font-weight:700;margin:0 -.75rem;padding:.2rem 3.5rem;border-bottom:1px solid #fafafa}.notice .notice-title i{position:absolute;top:50%;left:1.8rem;transform:translate(-50%,-50%)}.notice .notice-content{display:block;margin:2rem}.notice.note{background-color:#7e57c21a}.notice.note .notice-title{background-color:#673ab71a}.notice.note .notice-title i{color:#5e35b1}.notice.tip{background-color:#26a69a1a}.notice.tip .notice-title{background-color:#0096881a}.notice.tip .notice-title i{color:#00897b}.notice.example{background-color:#8d6e631a}.notice.example .notice-title{background-color:#7955481a}.notice.example .notice-title i{color:#6d4c41}.notice.question{background-color:#9ccc651a}.notice.question .notice-title{background-color:#8bc34a1a}.notice.question .notice-title i{color:#7cb342}.notice.info{background-color:#42a5f51a}.notice.info .notice-title{background-color:#2196f31a}.notice.info .notice-title i{color:#1e88e5}.notice.warning{background-color:#ffca281a}.notice.warning .notice-title{background-color:#ffc1071a}.notice.warning .notice-title i{color:#ffb300}.notice.error{background-color:#ef53501a}.notice.error .notice-title{background-color:#f443361a}.notice.error .notice-title i{color:#e53935}.navigation{height:6rem;width:100%}.navigation a,.navigation span{display:inline;font-size:1.7rem;font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,Helvetica,pingfang sc,STXihei,华文细黑,microsoft yahei,微软雅黑,SimSun,宋体,Heiti,黑体,sans-serif;font-weight:600;color:#212121}.navigation a:hover,.navigation a:focus{color:#1565c0}.navigation .navigation-title{letter-spacing:.1rem;text-transform:uppercase}.navigation .navigation-list{float:right;list-style:none;margin-bottom:0;margin-top:0}@media only screen and (max-width:768px){.navigation .navigation-list{position:relative;top:2rem;right:0;z-index:5;visibility:hidden;opacity:0;padding:0;max-height:0;width:100%;background-color:#fafafa;border-top:solid 2px #e0e0e0;border-bottom:solid 2px #e0e0e0;transition:opacity .25s,max-height .15s linear}}.navigation .navigation-list .navigation-item{float:left;margin:0;position:relative}@media only screen and (max-width:768px){.navigation .navigation-list .navigation-item{float:none!important;text-align:center}.navigation .navigation-list .navigation-item a,.navigation .navigation-list .navigation-item span{line-height:5rem}}.navigation .navigation-list .navigation-item a,.navigation .navigation-list .navigation-item span{margin-left:1rem;margin-right:1rem}@media only screen and (max-width:768px){.navigation .navigation-list .separator{display:none}}@media only screen and (max-width:768px){.navigation .navigation-list .menu-separator{border-top:2px solid #212121;margin:0 8rem}.navigation .navigation-list .menu-separator span{display:none}}.navigation #dark-mode-toggle{margin:1.7rem 0;font-size:2.4rem;line-height:inherit;bottom:2rem;left:2rem;z-index:100;position:fixed}.navigation #menu-toggle{display:none}@media only screen and (max-width:768px){.navigation #menu-toggle:checked+label>i{color:#e0e0e0}.navigation #menu-toggle:checked+label+ul{visibility:visible;opacity:1;max-height:100rem}}.navigation .menu-button{display:none}@media only screen and (max-width:768px){.navigation .menu-button{position:relative;display:block;font-size:2.4rem;font-weight:400}}.navigation .menu-button i:hover,.navigation .menu-button i:focus{color:#000}.navigation i{color:#212121;cursor:pointer}.navigation i:hover,.navigation i:focus{color:#1565c0}.pagination{margin-top:6rem;text-align:center;font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,Helvetica,pingfang sc,STXihei,华文细黑,microsoft yahei,微软雅黑,SimSun,宋体,Heiti,黑体,sans-serif}.pagination li{display:inline;text-align:center;font-weight:700}.pagination li span{margin:0;text-align:center;width:3.2rem}.pagination li a{font-weight:300}.pagination li a span{margin:0;text-align:center;width:3.2rem}.taxonomy li{display:inline-block;margin:.9rem}.taxonomy .taxonomy-element{display:block;padding:.3rem .9rem;background-color:#e0e0e0;border-radius:.6rem}.taxonomy .taxonomy-element a{color:#212121}.taxonomy .taxonomy-element a:active{color:#212121}.footer{width:100%;text-align:center;font-size:1.6rem;line-height:2rem;margin-bottom:1rem}.footer a{color:#1565c0}.float-container{bottom:2rem;right:2rem;z-index:100;position:fixed;font-size:1.6em}.float-container a{position:relative;display:inline-block;width:3rem;height:3rem;font-size:2rem;color:#000;background-color:#e0e0e0;border-radius:.2rem;opacity:50%;transition:all .25s ease-in}.float-container a:hover,.float-container a:focus{color:#1565c0;opacity:100%}@media only screen and (max-width:768px){.float-container a:hover,.float-container a:focus{color:#000;opacity:50%}}.float-container a i{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
\ No newline at end of file
@@ -0,0 +1 @@
+{"Target":"css/coder.min.708686f8ab8176e91d44fcbe488a0fe0333b94f405cf18a52383d67ba22f0ccb.css","MediaType":"text/css","Data":{"Integrity":"sha256-cIaG+KuBdukdRPy+SIoP4DM7lPQFzxilI4PWe6IvDMs="}}
\ No newline at end of file
Binary files a/static/gpgkey.asc and b/static/gpgkey.asc differ
@@ -0,0 +1,62 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+Hello everyone! Writing this quick article to announce the rotation and subsequent retiring of my old GPG key to a new one! I'm doing this mainly because my key has grown rather large, and I'd like to transition my key from using a 4096-bit RSA key to a Ed25519 key, which should provide functionally the same amount of security (author of Ed25519 quotes it equivalent to ~3000 bit RSA key, but I do know that really isn't the best way to compare these two things :P )
+
+So, with this announcement, I'd like to make the following points:
+* My old key is not compromised, but will be revoked after making this announcement
+* I will *not* use my old key to sign things, encrypt things, or authenticate with anything from this point onwards. If I do, something is terribly wrong.
+* This new key has been cross signed by my old key, but I won't be cross signing my old key with my new one, since that seems to be a "can go either way" situation in this case, and I don't see the benefit as the key is being revoked regardless.
+
+This is the information of the key that is being revoked:
+```
+pub rsa4096 2020-09-29 [C]
+ 2BC5D27B47EE5632F97A668012FAE298AAD38D3D
+uid [ultimate] Ryan Schanzenbacher <ryan@rschanz.org>
+uid [ultimate] Ryan Schanzenbacher <rjs1877@rit.edu>
+uid [ultimate] Ryan Schanzenbacher <rschanzenbacher@stoicproductions.org>
+uid [ultimate] [jpeg image of size 3237]
+sub rsa4096 2020-09-29 [A] [expires: 2022-10-03]
+sub rsa4096 2020-09-29 [E] [expires: 2022-10-03]
+sub rsa4096 2020-09-29 [S] [expires: 2022-10-03]
+```
+
+And this is the information of my new key:
+```
+pub ed25519 2022-02-21 [C]
+ 3E8745425417A3E388ACD906067DC3463E17741C
+uid [ultimate] Ryan Schanzenbacher <ryan@rschanz.org>
+uid [ultimate] [jpeg image of size 4437]
+uid [ultimate] Ryan Schanzenbacher <rjs1877@rit.edu>
+uid [ultimate] Ryan Schanzenbacher <rschanzenbacher@stoicproductions.org>
+sub ed25519 2022-02-21 [S] [expires: 2023-02-21]
+sub cv25519 2022-02-21 [E] [expires: 2023-02-21]
+sub ed25519 2022-02-21 [A] [expires: 2023-02-21]
+```
+
+I'd recommend to update your keychains if you happen to have my key, and the key hosted on the homepage of this website has been updated to reflect my new key.
+
+[Here is the signed version of this message](/misc/gpg_key_rotation_signed.txt)
+
+If you have any questions/comments/concerns, you can reach out to me at ryan@rschanz.org.
+
+Thanks!
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAEBCAAdFiEEgSnZdpRh8KnFgjqSPuc7pG1zrkwFAmITOQgACgkQPuc7pG1z
+rkx7yg/+KNqyJBnEgZJ8uBCopIf+JcmbK+Bob+K7l3dru9MrFXFW+clG47GsIlQE
+312Ucviyy4cmKDyUHtnjslOU2NHN6mSjFvqTlLORzfZ5btRvwrmq47OWe3/UR/u7
+0utyQpx8inxxQQxQpjQzidXenaAhdrHx0QaR/5vAnzANOH25NcLVGYfbFaHtmtd9
+vDboSBflfnOTdeBNSNph4geehn61IFVLyWB5KKACwiVzits3aho4ypbieARzVNlu
+wHkOwF+qopLkvVUJ7PxtXo4Wg/+bdXjB3ebaum7LDf4kElmZ2OZVOilCH6YbSLup
+5QgS/oVNe4OD9AAU46CrZoF1J7eI+v/uZRHBB0LWVKfC3ZDozrkLsTopDSY8WNzp
+4blH5K/sxsCqyuJiIf/70qLQ7wzrnxbSLd+wx9iVIdbC5aQKU69qHDmcVfhBjMRn
+IVx/imSBqCiaMprGAA9oVq8mPEWQy9VSKKowZaVobM6Ds7PF0eOcSBzNjfU6BJYH
+hi0nXswvGeIktSUjE5ADErGsWwQYUICrS3g+E7bX3N6IXM0KzlvkpLeqsOe6tR9U
+T6zpQNags2Ynya+1d5YwG34pupwxMhPA5eruY4IfG/19k7/rADIXP/ssYwOzJe10
+D0/bUELhJp+tdA2MeEdFc+6LnsE7NwdTCuFYBrmfjQpPaIVmneeIdQQBFggAHRYh
+BMRQVv/0iy7ynufwHIGw4iKj4jCOBQJiEzkIAAoJEIGw4iKj4jCOKRIBAO8dr/UQ
+G05VCW8BmsuUCp4XqitHgGWhANp39TMjBPcAAQDvjF6TX5kPDt817ZIwqmYxu6UJ
+XSqaYABaQcOegqvNDg==
+=BLA9
+-----END PGP SIGNATURE-----
Binary files /dev/null and b/static/resume/Schanzenbacher_Ryan_Resume.pdf differ
@@ -11,6 +11,31 @@
{{ partial "csp.html" . }}
{{ end }}
+ <style>
+ @keyframes snow {
+ 0% {
+ transform: translate(var(--x), var(--y));
+ }
+ 50% {
+ transform: translate(calc(var(--x) - var(--w)), calc(100vh - 5px));
+ }
+ 100% {
+ transform: translate(calc(var(--x) - var(--w)), calc(100vh - 5px)) scale(0);
+ }
+ }
+
+ .snow {
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background-color: white;
+ position: fixed;
+ transform: translate(var(--x), var(--y));
+ animation: snow var(--s) linear var(--d) infinite;
+ }
+
+ </style>
+
{{ with .Site.Params.author }}<meta name="author" content="{{ . }}">{{ end }}
<meta name="description" content="{{ .Description | default (.Summary | default .Site.Params.description ) }}">
<meta name="keywords" content="{{ (delimit .Keywords ",") | default .Site.Params.keywords }}">
@@ -26,7 +51,7 @@
<link rel="preload" href="/fonts/forkawesome-webfont.woff2?v=1.2.0" as="font" type="font/woff2" crossorigin>
- {{ if .Site.IsServer }}
+ {{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
@@ -37,7 +62,7 @@
{{ end }}
{{ if .Site.Params.rtl }}
- {{ if .Site.IsServer }}
+ {{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
@@ -49,7 +74,7 @@
{{ end }}
{{ if or (eq .Site.Params.colorScheme "auto") (eq .Site.Params.colorScheme "dark") }}
- {{ if .Site.IsServer }}
+ {{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder-dark.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
@@ -66,7 +91,7 @@
{{ range .Site.Params.customSCSS }}
{{/* We don't change the targetPath to because it's transparent to users */}}
- {{ if $.Site.IsServer }}
+ {{ if hugo.IsServer }}
{{ $cssOpts := (dict "enableSourceMap" true ) }}
{{ $styles := resources.Get . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
@@ -103,7 +128,10 @@
<body class="preload-transitions {{ $csClass }}{{ if .Site.Params.rtl }} rtl{{ end }}"
onload="{{ if .Site.Params.enableTwemoji }} twemoji.parse(document.body); {{ end }}"
>
- <div id=fireworksContainer style="position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none;"></div>
+
+ <div id="fireworksContainer" style="position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none; display: none;"></div>
+ <div id="snow" style="position: fixed; top: 0; left: 0; height: 100vh; width: 100vw; --s: 10s; --w: 50vw; --d: 0s; pointer-events: none; z-index: 1; display: none;"></div>
+
{{ partial "float" . }}
<main class="wrapper">
{{ partial "header.html" . }}
@@ -115,7 +143,7 @@
{{ partial "footer.html" . }}
</main>
- {{ if .Site.IsServer }}
+ {{ if hugo.IsServer }}
{{ $script := resources.Get "js/coder.js" }}
<script src="{{ $script.RelPermalink }}"></script>
{{ else }}
@@ -153,42 +181,61 @@
{{- partial "analytics/googletagmanager" . -}}
{{ end }}
- {{ if eq .URL "/" }}
- <script src="https://cdn.jsdelivr.net/npm/fireworks-js@latest/dist/fireworks.js"></script>
<script>
- const c = document.querySelector("#fireworksContainer")
- const f = new Fireworks(c, {
- "hue": {
- "min": 0,
- "max": 345
- },
- "delay": {
- "min": 15,
- "max": 20
- },
- "rocketsPoint": 27,
- "opacity": 0.5,
- "speed": 15,
- "acceleration": 1.1,
- "friction": 0.97,
- "gravity": 1.5,
- "particles": 150,
- "trace": 6,
- "explosion": 7,
- "autoresize": true,
- "brightness": {
- "min": 50,
- "max": 80,
- "decay": {
- "min": 0.015,
- "max": 0.03
- }
- },
- })
- f._randomRocketsPoint = true
- f.start()
+ const today = new Date();
+ const month = today.getMonth(); // 0 = Jan, 11 = Dec
+ const day = today.getDate();
+
+ const showFireworks = (month === 0 && day >= 1 && day <= 5);
+ const showSnow = (month === 11) || (month === 0 && day > 5 && day <= 31);
+
+ if (showFireworks) {
+ {{ if eq .RelPermalink "/" }}
+ document.getElementById("fireworksContainer").style.display = "block";
+ const script = document.createElement("script");
+ script.src = "https://cdn.jsdelivr.net/npm/fireworks-js@latest/dist/fireworks.js";
+ script.onload = () => {
+ const c = document.querySelector("#fireworksContainer");
+ const f = new Fireworks(c, {
+ "hue": { "min": 0, "max": 345 },
+ "delay": { "min": 45, "max": 60 },
+ "rocketsPoint": 27,
+ "opacity": 0.5,
+ "speed": 15,
+ "acceleration": 1.1,
+ "friction": 0.97,
+ "gravity": 1.5,
+ "particles": 150,
+ "trace": 6,
+ "explosion": 7,
+ "autoresize": true,
+ "brightness": {
+ "min": 50,
+ "max": 80,
+ "decay": { "min": 0.015, "max": 0.03 }
+ }
+ });
+ f._randomRocketsPoint = true;
+ f.start();
+ };
+ document.body.appendChild(script);
+ {{ end }}
+ } else if (showSnow) {
+ const snowContainer = document.getElementById("snow");
+ snowContainer.style.display = "block";
+
+ function r(min, max) {
+ return Math.random() * (max - min) + min;
+ }
+
+ for(const _ of Array(250).fill(0)) {
+ const el = document.createElement("div");
+ el.className = "snow";
+ el.style = `--x: ${r(0, 200)}vw; --y: -${r(0, 100)}vh; --d: ${r(-20, 20)}s; --w: ${r(40, 70)}vw; --s: ${r(12, 20)}s;`;
+ snowContainer.appendChild(el);
+ }
+ }
</script>
- {{ end }}
- </body>
+ </body>
</html>
@@ -3,7 +3,7 @@
<a class="navigation-title" href="{{ .Site.BaseURL | relLangURL }}">
{{ .Site.Title }}
</a>
- {{ if or .Site.Menus.main .Site.IsMultiLingual }}
+ {{ if or .Site.Menus.main hugo.IsMultilingual }}
<input type="checkbox" id="menu-toggle" />
<label class="menu-button float-right" for="menu-toggle">
<i class="fa fa-bars fa-fw" aria-hidden="true"></i>
@@ -16,7 +16,7 @@
</li>
{{ end }}
{{ end }}
- {{ if .Site.IsMultiLingual }}
+ {{ if hugo.IsMultilingual }}
{{ $node := . }}
{{ .Scratch.Set "separator" true }}
{{ range (default .Site.Home.AllTranslations .Translations) }}
@@ -14,7 +14,7 @@
{{ else }}
<h2>{{ .Site.Params.info }}</h2>
{{ end }}
- <h2>Happy New Year!</h2>
+ <!-- <h2>Happy New Year!</h2> -->
{{ with .Site.Params.social }}
<ul>
{{ range sort . "weight" }}
@@ -1,3 +1,3 @@
-{{- if and (not (eq (.Site.DisqusShortname | default "") "")) (eq (.Params.disableComments | default false) false) -}}
+{{- if and (not (eq (.Site.Config.Services.Disqus.Shortname | default "") "")) (eq (.Params.disableComments | default false) false) -}}
{{ template "_internal/disqus.html" . }}
{{- end -}}